LayoutTests/ChangeLog

 12011-02-18 Adam Barth <abarth@webkit.org>
 2
 3 Reviewed by NOBODY (OOPS!).
 4
 5 CSP's script-src should block JavaScript URLs
 6 https://bugs.webkit.org/show_bug.cgi?id=54787
 7
 8 Test how various CSP policies affect JavaScript URLs. We could test
 9 more contexts in the future, but this is a start.
 10
 11 * http/tests/security/contentSecurityPolicy/javascript-url-expected.txt: Added.
 12 * http/tests/security/contentSecurityPolicy/javascript-url.html: Added.
 13 * http/tests/security/contentSecurityPolicy/resources/javascript-url.pl: Added.
 14
1152011-02-18 Csaba Osztrogonác <ossy@webkit.org>
216
317 Unreviewed.

LayoutTests/http/tests/security/contentSecurityPolicy/javascript-url-expected.txt

 1ALERT: PASS
 2Loads an iframe which in turns tries to run JavaScript URLs. The test passes if the iframe doesn't alert 'fail'.
 3
 4

LayoutTests/http/tests/security/contentSecurityPolicy/javascript-url.html

 1<!DOCTYPE html>
 2<html>
 3<head>
 4<script>
 5if (window.layoutTestController)
 6 layoutTestController.dumpAsText();
 7</script>
 8</head>
 9<body>
 10 <p>
 11 Loads an iframe which in turns tries to run JavaScript URLs. The test passes if the iframe doesn't alert 'fail'.
 12 </p>
 13 <iframe src="http://127.0.0.1:8000/security/contentSecurityPolicy/resources/javascript-url.pl?should_run=no&csp=allow%20*%3B%20script-src%20'none'"></iframe>
 14 <iframe src="http://127.0.0.1:8000/security/contentSecurityPolicy/resources/javascript-url.pl?should_run=yes&csp=allow%20*%3B"></iframe>
 15</body>
 16</html>

LayoutTests/http/tests/security/contentSecurityPolicy/resources/javascript-url.pl

 1#!/usr/bin/perl -wT
 2use strict;
 3use CGI;
 4
 5my $cgi = new CGI;
 6
 7print "Content-Type: text/html; charset=UTF-8\n";
 8print "X-WebKit-CSP: ".$cgi->param('csp')."\n\n";
 9
 10my $text = "PASS";
 11$text = "FAIL" if $cgi->param('should_run') eq 'no';
 12
 13print "<!DOCTYPE html>\n";
 14print "<html>\n";
 15print "<body>\n";
 16print "<iframe src=\"javascript:alert('".$text."');\"></iframe>\n";
 17print "<object data=\"javascript:alert('".$text."');\"></object>\n";
 18print "<embed src=\"javascript:alert('".$text."');\"></embed>\n";
 19print "</html>\n";

Source/WebCore/ChangeLog

 12011-02-18 Adam Barth <abarth@webkit.org>
 2
 3 Reviewed by NOBODY (OOPS!).
 4
 5 CSP's script-src should block JavaScript URLs
 6 https://bugs.webkit.org/show_bug.cgi?id=54787
 7
 8 Blocking JavaScript URLs required some re-architecting of the lifetime
 9 of the ContentSecurityPolicy object. We now manage the lifetime the
 10 same way we manage the lifetime of the SecurityOrigin object. In
 11 particular, when SecurityOrigin inherits into an about:blank iframe, we
 12 inherit the CSP object as well. (This is covered by the test added in
 13 this patch.) In the future, we might consider making
 14 ContentSecurityPolicy a component of SecurityOrigin instead of a
 15 component of Document.
 16
 17 I noted the trickiness in
 18 http://www.w3.org/Security/wiki/Content_Security_Policies so that we'll
 19 make sure it gets defined properly in the spec.
 20
 21 Test: http/tests/security/contentSecurityPolicy/javascript-url.html
 22
 23 * bindings/ScriptControllerBase.cpp:
 24 (WebCore::ScriptController::executeIfJavaScriptURL):
 25 * dom/Document.cpp:
 26 (WebCore::Document::initSecurityContext):
 27 * dom/Document.h:
 28 (WebCore::Document::contentSecurityPolicy):
 29 * page/ContentSecurityPolicy.cpp:
 30 (WebCore::ContentSecurityPolicy::allowJavaScriptURLs):
 31 * page/ContentSecurityPolicy.h:
 32 (WebCore::ContentSecurityPolicy::create):
 33
1342011-02-15 Adrienne Walker <enne@google.com>
235
336 Reviewed by James Robinson.

Source/WebCore/bindings/ScriptControllerBase.cpp

@@bool ScriptController::executeIfJavaScriptURL(const KURL& url, ShouldReplaceDocu
7171 if (!protocolIsJavaScript(url))
7272 return false;
7373
74  if (!m_frame->page())
75  return true;
76 
77  if (!m_frame->page()->javaScriptURLsAreAllowed())
78  return true;
79 
80  if (m_frame->inViewSourceMode())
 74 if (!m_frame->page()
 75 || !m_frame->page()->javaScriptURLsAreAllowed()
 76 || !m_frame->document()->contentSecurityPolicy()->allowJavaScriptURLs()
 77 || m_frame->inViewSourceMode())
8178 return true;
8279
8380 // We need to hold onto the Frame here because executing script can

Source/WebCore/dom/Document.cpp

@@void Document::initSecurityContext()
44194419 // This can occur via document.implementation.createDocument().
44204420 m_cookieURL = KURL(ParsedURLString, "");
44214421 ScriptExecutionContext::setSecurityOrigin(SecurityOrigin::createEmpty());
 4422 m_contentSecurityPolicy = ContentSecurityPolicy::create();
44224423 return;
44234424 }
44244425
44254426 // In the common case, create the security context from the currently
4426  // loading URL.
 4427 // loading URL with a fresh content security policy.
44274428 m_cookieURL = m_url;
44284429 ScriptExecutionContext::setSecurityOrigin(SecurityOrigin::create(m_url, m_frame->loader()->sandboxFlags()));
 4430 m_contentSecurityPolicy = ContentSecurityPolicy::create();
44294431
44304432 if (SecurityOrigin::allowSubstituteDataAccessToLocal()) {
44314433 // If this document was loaded with substituteData, then the document can

@@void Document::initSecurityContext()
44694471 // We alias the SecurityOrigins to match Firefox, see Bug 15313
44704472 // https://bugs.webkit.org/show_bug.cgi?id=15313
44714473 ScriptExecutionContext::setSecurityOrigin(ownerFrame->document()->securityOrigin());
 4474 // FIXME: Consider moving m_contentSecurityPolicy into SecurityOrigin.
 4475 m_contentSecurityPolicy = ownerFrame->document()->contentSecurityPolicy();
44724476 }
44734477}
44744478

Source/WebCore/dom/Document.h

@@public:
11071107
11081108 void initDNSPrefetch();
11091109
1110  ContentSecurityPolicy* contentSecurityPolicy() { return &m_contentSecurityPolicy; }
 1110 ContentSecurityPolicy* contentSecurityPolicy() { return m_contentSecurityPolicy.get(); }
11111111
11121112protected:
11131113 Document(Frame*, const KURL&, bool isXHTML, bool isHTML);

@@private:
14131413 OwnPtr<ScriptedAnimationController> m_scriptedAnimationController;
14141414#endif
14151415
1416  ContentSecurityPolicy m_contentSecurityPolicy;
 1416 RefPtr<ContentSecurityPolicy> m_contentSecurityPolicy;
14171417};
14181418
14191419inline bool Document::hasElementWithId(AtomicStringImpl* id) const

Source/WebCore/page/ContentSecurityPolicy.cpp

@@void ContentSecurityPolicy::didReceiveHeader(const String& header)
6363 m_havePolicy = true;
6464}
6565
 66bool ContentSecurityPolicy::allowJavaScriptURLs() const
 67{
 68 return !m_scriptSrc;
 69}
 70
6671bool ContentSecurityPolicy::canLoadExternalScriptFromSrc(const String& url) const
6772{
6873 return !m_scriptSrc || m_scriptSrc->allows(KURL(ParsedURLString, url));

Source/WebCore/page/ContentSecurityPolicy.h

@@namespace WebCore {
3333
3434class CSPDirective;
3535
36 class ContentSecurityPolicy {
37  WTF_MAKE_NONCOPYABLE(ContentSecurityPolicy);
 36class ContentSecurityPolicy : public RefCounted<ContentSecurityPolicy> {
3837public:
39  ContentSecurityPolicy();
 38 static PassRefPtr<ContentSecurityPolicy> create() { return adoptRef(new ContentSecurityPolicy); }
4039 ~ContentSecurityPolicy();
4140
4241 void didReceiveHeader(const String&);
 42
 43 bool allowJavaScriptURLs() const;
 44 // FIXME: Rename canLoadExternalScriptFromSrc to allowScriptFromURL.
4345 bool canLoadExternalScriptFromSrc(const String& url) const;
4446
4547private:
 48 ContentSecurityPolicy();
 49
4650 void parse(const String&);
4751 void parseDirective(const UChar*& pos, const UChar* end, Vector<UChar, 32>& name, Vector<UChar, 64>& value);
4852 void emitDirective(const String& name, const String& value);