Changeset 133006 in webkit


Ignore:
Timestamp:
Oct 31, 2012 2:59:45 AM (11 years ago)
Author:
mkwst@chromium.org
Message:

Script run from an isolated world should bypass a page's CSP.
https://bugs.webkit.org/show_bug.cgi?id=97398

Reviewed by Adam Barth.

Source/WebCore:

A page's Content Security Policy currently applies to all resources
loaded, regardless of their source. That generally makes sense, but
proves problematic when considering script run from an isolated
world (Chrome extensions, for instance). These scripts should be allowed
to inject resources into a page's DOM without eiher being restricted by
the page's active CSP, or generating violation reports that spam the
page owner.

Ideally, the isolated world could define its own Content Security Policy
which should be applied to resources it loads. For the moment, this
patch accepts a String that we can parse later on, but only uses it in
a binary way. If a non-empty policy String is provided, we bypass the
main world's CSP checks. If an empty String is provided, the main
world's CSP checks remain active.

Test: http/tests/security/isolatedWorld/bypass-main-world-csp.html

(WebCore::isolatedWorldContentSecurityPolicies):
(WebCore::DOMWrapperWorld::isolatedWorldHasContentSecurityPolicy):
(WebCore::DOMWrapperWorld::setIsolatedWorldContentSecurityPolicy):
(WebCore::DOMWrapperWorld::clearIsolatedWorldContentSecurityPolicy):

  • bindings/v8/DOMWrapperWorld.h:

(DOMWrapperWorld):

Mechanisms for setting and clearing Content Security Policies from
isolated worlds; implemented in the same HashMappy way as
SecurityOrigin.

  • bindings/v8/ScriptController.cpp:

(WebCore::ScriptController::shouldBypassMainWorldContentSecurityPolicy):
(WebCore):

  • bindings/v8/ScriptController.h:

(ScriptController):

Adding a method to ScriptController to query the state of the
current world's Content Security Policy. We'll drop this once we can
apply a policy more directly, but for the moment it's necessary for
the next bit.

  • loader/cache/CachedResourceLoader.cpp:

(WebCore::CachedResourceLoader::canRequest):

Check the new ScriptController method, and only perform CSP checks
when loading resources if we're executing code from the main world,
or an isolated world with no Content Security Policy set.

Source/WebKit/chromium:

  • public/WebFrame.h:

(WebFrame):

  • src/WebFrameImpl.cpp:

(WebKit::WebFrameImpl::setIsolatedWorldSecurityOrigin):
(WebKit):
(WebKit::WebFrameImpl::setIsolatedWorldContentSecurityPolicy):

  • src/WebFrameImpl.h:

(WebFrameImpl):

Piping a Content Security Policy through WebFrame, in the same way
we're currently doing for SecurityOrigin. As a drive-by, this also
uses the static method on DOMWrapperWindow to set the security
origin, rather than routing through the frame's ScriptController.

Tools:

  • DumpRenderTree/chromium/DRTTestRunner.cpp:

(DRTTestRunner::DRTTestRunner):
(DRTTestRunner::setIsolatedWorldContentSecurityPolicy):

  • DumpRenderTree/chromium/DRTTestRunner.h:

(DRTTestRunner):

Adding a mechanism to set the Content Security Policy for an
isolated world to Chromium's testRunner.

LayoutTests:

  • http/tests/security/isolatedWorld/bypass-main-world-csp-expected.txt: Added.
  • http/tests/security/isolatedWorld/bypass-main-world-csp.html: Added.
  • platform/efl/TestExpectations:
  • platform/mac/TestExpectations:
  • platform/qt/TestExpectations:
  • platform/win/TestExpectations:

Skip the new tests on ports that don't support the new functionality

Location:
trunk
Files:
2 added
19 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r133005 r133006  
     12012-10-31  Mike West  <mkwst@chromium.org>
     2
     3        Script run from an isolated world should bypass a page's CSP.
     4        https://bugs.webkit.org/show_bug.cgi?id=97398
     5
     6        Reviewed by Adam Barth.
     7
     8        * http/tests/security/isolatedWorld/bypass-main-world-csp-expected.txt: Added.
     9        * http/tests/security/isolatedWorld/bypass-main-world-csp.html: Added.
     10        * platform/efl/TestExpectations:
     11        * platform/mac/TestExpectations:
     12        * platform/qt/TestExpectations:
     13        * platform/win/TestExpectations:
     14            Skip the new tests on ports that don't support the new functionality
     15
    1162012-10-31  Pavel Podivilov  <podivilov@google.com>
    217
  • trunk/LayoutTests/platform/efl/TestExpectations

    r133000 r133006  
    10221022webkit.org/b/61540 inspector/extensions/extensions-audits-content-script.html [ Failure ]
    10231023webkit.org/b/61540 inspector/extensions/extensions-eval-content-script.html [ Failure ]
     1024
     1025# JSC also doesn't support setIsolatedWorldContentSecurityPolicy
     1026webkit.org/b/100815 http/tests/security/isolatedWorld/bypass-main-world-csp.html [ Failure ]
    10241027
    10251028#__worldID is undefined in isolated world
  • trunk/LayoutTests/platform/mac/TestExpectations

    r132843 r133006  
    428428# JSC does not support setIsolatedWorldSecurityOrigin (http://webkit.org/b/61540)
    429429http/tests/security/isolatedWorld/cross-origin-xhr.html
     430
     431# JSC also doesn't support setIsolatedWorldContentSecurityPolicy (webkit.org/b/100815)
     432http/tests/security/isolatedWorld/bypass-main-world-csp.html
    430433
    431434# https://bugs.webkit.org/show_bug.cgi?id=63282 layerTreeAsText doesn't work for iframes
  • trunk/LayoutTests/platform/qt/TestExpectations

    r132929 r133006  
    341341http/tests/security/isolatedWorld/cross-origin-xhr.html
    342342
     343# JSC also doesn't support setIsolatedWorldContentSecurityPolicy (webkit.org/b/100815)
     344http/tests/security/isolatedWorld/bypass-main-world-csp.html
     345
    343346# This test is for clients that choose to make the missing plugin indicator a button
    344347plugins/clicking-missing-plugin-fires-delegate.html
  • trunk/LayoutTests/platform/win/TestExpectations

    r132964 r133006  
    14821482# JSC does not support setIsolatedWorldSecurityOrigin (http://webkit.org/b/61540)
    14831483http/tests/security/isolatedWorld/cross-origin-xhr.html
     1484
     1485# JSC also doesn't support setIsolatedWorldContentSecurityPolicy (webkit.org/b/100815)
     1486http/tests/security/isolatedWorld/bypass-main-world-csp.html
    14841487
    14851488# ENABLE(WEBGL) is disabled
  • trunk/Source/WebCore/ChangeLog

    r132999 r133006  
     12012-10-31  Mike West  <mkwst@chromium.org>
     2
     3        Script run from an isolated world should bypass a page's CSP.
     4        https://bugs.webkit.org/show_bug.cgi?id=97398
     5
     6        Reviewed by Adam Barth.
     7
     8        A page's Content Security Policy currently applies to all resources
     9        loaded, regardless of their source. That generally makes sense, but
     10        proves problematic when considering script run from an isolated
     11        world (Chrome extensions, for instance). These scripts should be allowed
     12        to inject resources into a page's DOM without eiher being restricted by
     13        the page's active CSP, or generating violation reports that spam the
     14        page owner.
     15
     16        Ideally, the isolated world could define its own Content Security Policy
     17        which should be applied to resources it loads. For the moment, this
     18        patch accepts a String that we can parse later on, but only uses it in
     19        a binary way. If a non-empty policy String is provided, we bypass the
     20        main world's CSP checks. If an empty String is provided, the main
     21        world's CSP checks remain active.
     22
     23        Test: http/tests/security/isolatedWorld/bypass-main-world-csp.html
     24
     25        (WebCore::isolatedWorldContentSecurityPolicies):
     26        (WebCore::DOMWrapperWorld::isolatedWorldHasContentSecurityPolicy):
     27        (WebCore::DOMWrapperWorld::setIsolatedWorldContentSecurityPolicy):
     28        (WebCore::DOMWrapperWorld::clearIsolatedWorldContentSecurityPolicy):
     29        * bindings/v8/DOMWrapperWorld.h:
     30        (DOMWrapperWorld):
     31            Mechanisms for setting and clearing Content Security Policies from
     32            isolated worlds; implemented in the same HashMappy way as
     33            SecurityOrigin.
     34        * bindings/v8/ScriptController.cpp:
     35        (WebCore::ScriptController::shouldBypassMainWorldContentSecurityPolicy):
     36        (WebCore):
     37        * bindings/v8/ScriptController.h:
     38        (ScriptController):
     39            Adding a method to ScriptController to query the state of the
     40            current world's Content Security Policy. We'll drop this once we can
     41            apply a policy more directly, but for the moment it's necessary for
     42            the next bit.
     43        * loader/cache/CachedResourceLoader.cpp:
     44        (WebCore::CachedResourceLoader::canRequest):
     45            Check the new ScriptController method, and only perform CSP checks
     46            when loading resources if we're executing code from the main world,
     47            or an isolated world with no Content Security Policy set.
     48
    1492012-10-31  Tim Horton  <timothy_horton@apple.com>
    250
  • trunk/Source/WebCore/bindings/js/ScriptController.h

    r130612 r133006  
    161161#endif
    162162
     163    // FIXME: Stub for parity with V8 implementation. http://webkit.org/b/100815
     164    bool shouldBypassMainWorldContentSecurityPolicy() { return false; }
     165
    163166private:
    164167    JSDOMWindowShell* initScript(DOMWrapperWorld* world);
  • trunk/Source/WebCore/bindings/v8/DOMWrapperWorld.cpp

    r131629 r133006  
    144144}
    145145
     146typedef HashMap<int, bool> IsolatedWorldContentSecurityPolicyMap;
     147static IsolatedWorldContentSecurityPolicyMap& isolatedWorldContentSecurityPolicies()
     148{
     149    ASSERT(isMainThread());
     150    DEFINE_STATIC_LOCAL(IsolatedWorldContentSecurityPolicyMap, map, ());
     151    return map;
     152}
     153
     154bool DOMWrapperWorld::isolatedWorldHasContentSecurityPolicy()
     155{
     156    ASSERT(this->isIsolatedWorld());
     157    IsolatedWorldContentSecurityPolicyMap& policies = isolatedWorldContentSecurityPolicies();
     158    IsolatedWorldContentSecurityPolicyMap::iterator it = policies.find(worldId());
     159    return it == policies.end() ? false : it->value;
     160}
     161
     162void DOMWrapperWorld::setIsolatedWorldContentSecurityPolicy(int worldID, const String& policy)
     163{
     164    ASSERT(DOMWrapperWorld::isIsolatedWorldId(worldID));
     165    if (!policy.isEmpty())
     166        isolatedWorldContentSecurityPolicies().set(worldID, true);
     167    else
     168        isolatedWorldContentSecurityPolicies().remove(worldID);
     169}
     170
     171void DOMWrapperWorld::clearIsolatedWorldContentSecurityPolicy(int worldID)
     172{
     173    ASSERT(DOMWrapperWorld::isIsolatedWorldId(worldID));
     174    isolatedWorldContentSecurityPolicies().remove(worldID);
     175}
     176
    146177} // namespace WebCore
  • trunk/Source/WebCore/bindings/v8/DOMWrapperWorld.h

    r132458 r133006  
    3838#include <wtf/RefCounted.h>
    3939#include <wtf/RefPtr.h>
     40#include <wtf/text/WTFString.h>
    4041
    4142namespace WebCore {
     
    5859    static void clearIsolatedWorldSecurityOrigin(int worldID);
    5960    SecurityOrigin* isolatedWorldSecurityOrigin();
     61
     62    // Associated an isolated world with a Content Security Policy. Resources
     63    // embedded into the main world's DOM from script executed in an isolated
     64    // world should be restricted based on the isolated world's DOM, not the
     65    // main world's.
     66    //
     67    // FIXME: Right now, resource injection simply bypasses the main world's
     68    // DOM. More work is necessary to allow the isolated world's policy to be
     69    // applied correctly.
     70    static void setIsolatedWorldContentSecurityPolicy(int worldID, const String& policy);
     71    static void clearIsolatedWorldContentSecurityPolicy(int worldID);
     72    bool isolatedWorldHasContentSecurityPolicy();
     73
    6074    // FIXME: this is a workaround for a problem in WebViewImpl.
    6175    // Do not use this anywhere else!!
  • trunk/Source/WebCore/bindings/v8/ScriptController.cpp

    r132517 r133006  
    397397}
    398398
     399bool ScriptController::shouldBypassMainWorldContentSecurityPolicy()
     400{
     401    if (V8DOMWindowShell* isolatedWorldShell = V8DOMWindowShell::getEntered())
     402        return isolatedWorldShell->world()->isolatedWorldHasContentSecurityPolicy();
     403    return false;
     404}
     405
    399406TextPosition ScriptController::eventHandlerPosition() const
    400407{
  • trunk/Source/WebCore/bindings/v8/ScriptController.h

    r132505 r133006  
    108108    void evaluateInIsolatedWorld(int worldID, const Vector<ScriptSourceCode>& sources, int extensionGroup, Vector<ScriptValue>* results);
    109109
     110    // Returns true if the current world is isolated, and has its own Content
     111    // Security Policy. In this case, the policy of the main world should be
     112    // ignored when evaluating resources injected into the DOM.
     113    bool shouldBypassMainWorldContentSecurityPolicy();
     114
    110115    // FIXME: Remove references to this call in chromium and delete it.
    111116    inline static void setIsolatedWorldSecurityOrigin(int worldID, PassRefPtr<SecurityOrigin> origin)
  • trunk/Source/WebCore/loader/cache/CachedResourceLoader.cpp

    r132869 r133006  
    302302    if (document() && !document()->securityOrigin()->canDisplay(url)) {
    303303        if (!forPreload)
    304             FrameLoader::reportLocalLoadFailed(document()->frame(), url.string());
     304            FrameLoader::reportLocalLoadFailed(frame(), url.string());
    305305        LOG(ResourceLoading, "CachedResourceLoader::requestResource URL was not allowed by SecurityOrigin::canDisplay");
    306306        return 0;
     
    311311        return false;
    312312#endif
     313
     314    bool shouldBypassMainWorldContentSecurityPolicy = (frame() && frame()->script()->shouldBypassMainWorldContentSecurityPolicy());
    313315
    314316    // Some types of resources can be loaded only from the same origin.  Other
     
    353355#endif
    354356    case CachedResource::Script:
    355         if (!m_document->contentSecurityPolicy()->allowScriptFromSource(url))
     357        if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url))
    356358            return false;
    357359
     
    369371#endif
    370372    case CachedResource::CSSStyleSheet:
    371         if (!m_document->contentSecurityPolicy()->allowStyleFromSource(url))
     373        if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowStyleFromSource(url))
    372374            return false;
    373375        break;
     
    376378#endif
    377379    case CachedResource::ImageResource:
    378         if (!m_document->contentSecurityPolicy()->allowImageFromSource(url))
     380        if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowImageFromSource(url))
    379381            return false;
    380382        break;
    381383    case CachedResource::FontResource: {
    382         if (!m_document->contentSecurityPolicy()->allowFontFromSource(url))
     384        if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowFontFromSource(url))
    383385            return false;
    384386        break;
     
    395397        // Cues aren't called out in the CPS spec yet, but they only work with a media element
    396398        // so use the media policy.
    397         if (!m_document->contentSecurityPolicy()->allowMediaFromSource(url))
     399        if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowMediaFromSource(url))
    398400            return false;
    399401        break;
  • trunk/Source/WebKit/chromium/ChangeLog

    r132946 r133006  
     12012-10-31  Mike West  <mkwst@chromium.org>
     2
     3        Script run from an isolated world should bypass a page's CSP.
     4        https://bugs.webkit.org/show_bug.cgi?id=97398
     5
     6        Reviewed by Adam Barth.
     7
     8        * public/WebFrame.h:
     9        (WebFrame):
     10        * src/WebFrameImpl.cpp:
     11        (WebKit::WebFrameImpl::setIsolatedWorldSecurityOrigin):
     12        (WebKit):
     13        (WebKit::WebFrameImpl::setIsolatedWorldContentSecurityPolicy):
     14        * src/WebFrameImpl.h:
     15        (WebFrameImpl):
     16            Piping a Content Security Policy through WebFrame, in the same way
     17            we're currently doing for SecurityOrigin. As a drive-by, this also
     18            uses the static method on DOMWrapperWindow to set the security
     19            origin, rather than routing through the frame's ScriptController.
     20
    1212012-10-30  W. James MacLean  <wjmaclean@chromium.org>
    222
  • trunk/Source/WebKit/chromium/public/WebFrame.h

    r131223 r133006  
    253253        int worldID, const WebSecurityOrigin&) = 0;
    254254
     255    // Associates a content security policy with an isolated world. This policy
     256    // should be used when evaluating script in the isolated world, and should
     257    // also replace a protected resource's CSP when evaluating resources
     258    // injected into the DOM.
     259    //
     260    // FIXME: Setting this simply bypasses the protected resource's CSP. It
     261    //     doesn't yet restrict the isolated world to the provided policy.
     262    virtual void setIsolatedWorldContentSecurityPolicy(
     263        int worldID, const WebString&) = 0;
     264
    255265    // Logs to the console associated with this frame.
    256266    virtual void addMessageToConsole(const WebConsoleMessage&) = 0;
  • trunk/Source/WebKit/chromium/src/WebFrameImpl.cpp

    r132746 r133006  
    8383#include "DOMWindow.h"
    8484#include "DOMWindowIntents.h"
     85#include "DOMWrapperWorld.h"
    8586#include "DeliveredIntent.h"
    8687#include "DeliveredIntentClientImpl.h"
     
    827828{
    828829    ASSERT(frame());
    829     frame()->script()->setIsolatedWorldSecurityOrigin(worldID, securityOrigin.get());
     830    DOMWrapperWorld::setIsolatedWorldSecurityOrigin(worldID, securityOrigin.get());
     831}
     832
     833void WebFrameImpl::setIsolatedWorldContentSecurityPolicy(int worldID, const WebString& policy)
     834{
     835    ASSERT(frame());
     836    DOMWrapperWorld::setIsolatedWorldContentSecurityPolicy(worldID, policy);
    830837}
    831838
  • trunk/Source/WebKit/chromium/src/WebFrameImpl.h

    r129947 r133006  
    115115        int extensionGroup);
    116116    virtual void setIsolatedWorldSecurityOrigin(int worldID, const WebSecurityOrigin&);
     117    virtual void setIsolatedWorldContentSecurityPolicy(int worldID, const WebString&);
    117118    virtual void addMessageToConsole(const WebConsoleMessage&);
    118119    virtual void collectGarbage();
  • trunk/Tools/ChangeLog

    r133000 r133006  
     12012-10-31  Mike West  <mkwst@chromium.org>
     2
     3        Script run from an isolated world should bypass a page's CSP.
     4        https://bugs.webkit.org/show_bug.cgi?id=97398
     5
     6        Reviewed by Adam Barth.
     7
     8        * DumpRenderTree/chromium/DRTTestRunner.cpp:
     9        (DRTTestRunner::DRTTestRunner):
     10        (DRTTestRunner::setIsolatedWorldContentSecurityPolicy):
     11        * DumpRenderTree/chromium/DRTTestRunner.h:
     12        (DRTTestRunner):
     13            Adding a mechanism to set the Content Security Policy for an
     14            isolated world to Chromium's testRunner.
     15
    1162012-10-31  Michał Pakuła vel Rutka  <m.pakula@samsung.com>
    217
  • trunk/Tools/DumpRenderTree/chromium/DRTTestRunner.cpp

    r132478 r133006  
    158158    bindMethod("evaluateScriptInIsolatedWorldAndReturnValue", &DRTTestRunner::evaluateScriptInIsolatedWorldAndReturnValue);
    159159    bindMethod("setIsolatedWorldSecurityOrigin", &DRTTestRunner::setIsolatedWorldSecurityOrigin);
     160    bindMethod("setIsolatedWorldContentSecurityPolicy", &DRTTestRunner::setIsolatedWorldContentSecurityPolicy);
    160161    bindMethod("execCommand", &DRTTestRunner::execCommand);
    161162    bindMethod("forceRedSelectionColors", &DRTTestRunner::forceRedSelectionColors);
     
    14021403        origin = WebSecurityOrigin::createFromString(cppVariantToWebString(arguments[1]));
    14031404    m_shell->webView()->focusedFrame()->setIsolatedWorldSecurityOrigin(arguments[0].toInt32(), origin);
     1405}
     1406
     1407void DRTTestRunner::setIsolatedWorldContentSecurityPolicy(const CppArgumentList& arguments, CppVariant* result)
     1408{
     1409    result->setNull();
     1410
     1411    if (arguments.size() != 2 || !arguments[0].isNumber() || !arguments[1].isString())
     1412        return;
     1413
     1414    m_shell->webView()->focusedFrame()->setIsolatedWorldContentSecurityPolicy(arguments[0].toInt32(), cppVariantToWebString(arguments[1]));
    14041415}
    14051416
  • trunk/Tools/DumpRenderTree/chromium/DRTTestRunner.h

    r132781 r133006  
    298298    void evaluateScriptInIsolatedWorld(const CppArgumentList&, CppVariant*);
    299299    void setIsolatedWorldSecurityOrigin(const CppArgumentList&, CppVariant*);
     300    void setIsolatedWorldContentSecurityPolicy(const CppArgumentList&, CppVariant*);
    300301
    301302    // The fallback method is called when a nonexistent method is called on
Note: See TracChangeset for help on using the changeset viewer.