Changeset 125531 in webkit
- Timestamp:
- Aug 14, 2012 2:16:51 AM (12 years ago)
- Location:
- trunk
- Files:
-
- 20 added
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r125529 r125531 1 2012-08-14 Mike West <mkwst@chromium.org> 2 3 Implement the plugin-types Content Security Policy directive. 4 https://bugs.webkit.org/show_bug.cgi?id=91919 5 6 Reviewed by Adam Barth. 7 8 * http/tests/plugins/resources/mock-plugin-unknown-type.pl: 9 Adding a mock plugin resource that is served with a type that WebKit 10 doesn't understand. Using it to test a confusion attack in 11 plugintypes-url-02. 12 * http/tests/security/contentSecurityPolicy/1.1/plugintypes-invalid-expected.txt: Added. 13 * http/tests/security/contentSecurityPolicy/1.1/plugintypes-invalid.html: Added. 14 * http/tests/security/contentSecurityPolicy/1.1/plugintypes-mismatched-data-expected.txt: Added. 15 * http/tests/security/contentSecurityPolicy/1.1/plugintypes-mismatched-data.html: Added. 16 * http/tests/security/contentSecurityPolicy/1.1/plugintypes-mismatched-url-expected.txt: Added. 17 * http/tests/security/contentSecurityPolicy/1.1/plugintypes-mismatched-url.html: Added. 18 * http/tests/security/contentSecurityPolicy/1.1/plugintypes-notype-data-expected.txt: Added. 19 * http/tests/security/contentSecurityPolicy/1.1/plugintypes-notype-data.html: Added. 20 * http/tests/security/contentSecurityPolicy/1.1/plugintypes-notype-url-expected.txt: Added. 21 * http/tests/security/contentSecurityPolicy/1.1/plugintypes-notype-url.html: Added. 22 * http/tests/security/contentSecurityPolicy/1.1/plugintypes-nourl-allowed-expected.txt: Added. 23 * http/tests/security/contentSecurityPolicy/1.1/plugintypes-nourl-allowed.html: Added. 24 * http/tests/security/contentSecurityPolicy/1.1/plugintypes-nourl-blocked-expected.txt: Added. 25 * http/tests/security/contentSecurityPolicy/1.1/plugintypes-nourl-blocked.html: Added. 26 * http/tests/security/contentSecurityPolicy/1.1/plugintypes-url-01-expected.txt: Added. 27 * http/tests/security/contentSecurityPolicy/1.1/plugintypes-url-01.html: Added. 28 * http/tests/security/contentSecurityPolicy/1.1/plugintypes-url-02-expected.txt: Added. 29 * http/tests/security/contentSecurityPolicy/1.1/plugintypes-url-02.html: Added. 30 * http/tests/security/contentSecurityPolicy/object-src-none-allowed.html: 31 * http/tests/security/contentSecurityPolicy/object-src-none-blocked.html: 32 Renaming the `q` parameter to `plugin` in these two tests. 33 * http/tests/security/contentSecurityPolicy/resources/echo-object-data.pl: 34 Add output of explicit MIME types to the object data renderer, and 35 changed the `q` parameter to be slightly less confusingly named. 36 It's now `plugin`. 37 * http/tests/security/contentSecurityPolicy/resources/multiple-iframe-plugin-test.js: Added. 38 Copy `multiple-iframe-test.js`, and add in plugin-specific details, 39 like `plugin`, `log`, and `type`. 40 (test): 41 (finishTesting): 42 1 43 2012-08-14 Hans Wennborg <hans@chromium.org> 2 44 -
trunk/LayoutTests/http/tests/security/contentSecurityPolicy/object-src-none-allowed.html
r123978 r125531 10 10 </head> 11 11 <body> 12 <iframe src="http://127.0.0.1:8000/security/contentSecurityPolicy/resources/echo-object-data.pl? q=data:application/x-webkit-test-netscape,logifloaded&log=PASS!&csp=img-src%20'none'"></iframe>12 <iframe src="http://127.0.0.1:8000/security/contentSecurityPolicy/resources/echo-object-data.pl?plugin=data:application/x-webkit-test-netscape,logifloaded&log=PASS!&csp=img-src%20'none'"></iframe> 13 13 </body> 14 14 </html> -
trunk/LayoutTests/http/tests/security/contentSecurityPolicy/object-src-none-blocked.html
r123978 r125531 10 10 </head> 11 11 <body> 12 <iframe src="http://127.0.0.1:8000/security/contentSecurityPolicy/resources/echo-object-data.pl? q=data:application/x-webkit-test-netscape,logifloaded&log=FAIL&csp=object-src%20'none'"></iframe>12 <iframe src="http://127.0.0.1:8000/security/contentSecurityPolicy/resources/echo-object-data.pl?plugin=data:application/x-webkit-test-netscape,logifloaded&log=FAIL&csp=object-src%20'none'"></iframe> 13 13 </body> 14 14 </html> -
trunk/LayoutTests/http/tests/security/contentSecurityPolicy/resources/echo-object-data.pl
r123978 r125531 12 12 print "<body>\n"; 13 13 print "<script src=\"/plugins/resources/mock-plugin-logger.js\"></script>\n"; 14 print "<object data=\"".$cgi->param('q')."\" log=\"".$cgi->param('log')."\"></object>\n"; 14 print "<object data=\"".$cgi->param('plugin')."\"\n"; 15 print " log=\"".$cgi->param('log')."\"\n" if $cgi->param('log'); 16 print " type=\"".$cgi->param('type')."\"\n" if $cgi->param('type'); 17 print "></object>\n"; 15 18 print "</body>\n"; 16 19 print "</html>\n"; -
trunk/Source/WebCore/ChangeLog
r125530 r125531 1 2012-08-14 Mike West <mkwst@chromium.org> 2 3 Implement the plugin-types Content Security Policy directive. 4 https://bugs.webkit.org/show_bug.cgi?id=91919 5 6 Reviewed by Adam Barth. 7 8 The CSP 1.1 editor's draft defines the 'plugin-types' directive as a 9 mechanism for whitelisting only specific types of plugin content on a 10 page. A protected resource might trust only Flash content, for instance, 11 and could enforce that preference via a Content Security Policy of 12 'plugin-types application/x-shockwave-flash'. Flash would load, no other 13 plugin type would. 14 15 Specification details available at: https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html#plugin-types--experimental 16 17 This experimental directive is gated on the ENABLE_CSP_NEXT flag, which 18 is currently only enabled in Chromium. 19 20 Tests: http/tests/security/contentSecurityPolicy/1.1/plugintypes-invalid.html 21 http/tests/security/contentSecurityPolicy/1.1/plugintypes-mismatched-data.html 22 http/tests/security/contentSecurityPolicy/1.1/plugintypes-mismatched-url.html 23 http/tests/security/contentSecurityPolicy/1.1/plugintypes-notype-data.html 24 http/tests/security/contentSecurityPolicy/1.1/plugintypes-notype-url.html 25 http/tests/security/contentSecurityPolicy/1.1/plugintypes-nourl-allowed.html 26 http/tests/security/contentSecurityPolicy/1.1/plugintypes-nourl-blocked.html 27 http/tests/security/contentSecurityPolicy/1.1/plugintypes-url-01.html 28 http/tests/security/contentSecurityPolicy/1.1/plugintypes-url-02.html 29 30 * loader/SubframeLoader.cpp: 31 (WebCore::SubframeLoader::pluginIsLoadable): 32 Adding a check against 'allowPluginType', and passing in both the 33 MIME type of the plugin, as well as the declared MIME type from the 34 object/embed element (ensuring that we do this correctly, even if 35 we're inside a PluginDocument). 36 (WebCore::SubframeLoader::createJavaAppletWidget): 37 Same as 'pluginIsLoadable', but hard-coded to 38 'application/x-java-applet'. 39 * page/ContentSecurityPolicy.cpp: 40 (CSPDirectiveList): 41 (WebCore::CSPDirectiveList::logInvalidPluginTypes): 42 Plugin types that don't match the grammar ('not/a/mime/type') are 43 logged to the console, and ignored for purposes of matching. 44 (WebCore): 45 (WebCore::CSPDirectiveList::checkPluginType): 46 Given both the plugin type and the declared type attribute, returns 47 true if both types match, and are contained in the list of accepted 48 plugin types. 49 (WebCore::CSPDirectiveList::checkPluginTypeAndReportViolation): 50 Calls out to checkPluginType, and reports a violation if that check 51 fails. 52 (WebCore::CSPDirectiveList::allowPluginType): 53 Analog to the other 'CSPDirectiveList::allowXXX' methods, this 54 branches between simply checking the type against the policy, and 55 checking against the policy and then reporting violations. 56 (WebCore::CSPDirectiveList::parsePluginTypes): 57 Given a directive value, parse out the media types contained within 58 by splitting on spaces, and validating each token. Valid tokens are 59 added to 'm_pluginTypes' for use in 'checkPluginType'. 60 (WebCore::CSPDirectiveList::addDirective): 61 Wire up 'plugin-types' as a valid directive (if the ENABLE_CSP_NEXT 62 flag is set). This has been combined with the other implemented 1.1 63 header, 'script-nonce'. 64 (WebCore::ContentSecurityPolicy::allowPluginType): 65 The public interface to this set of functionality. 66 * page/ContentSecurityPolicy.h: 67 1 68 2012-08-14 Charles Wei <charles.wei@torchmobile.com.cn> 2 69 -
trunk/Source/WebCore/loader/SubframeLoader.cpp
r124704 r125531 127 127 } 128 128 129 if (!document()->contentSecurityPolicy()->allowObjectFromSource(url)) { 129 String declaredMimeType = document()->isPluginDocument() ? 130 document()->ownerElement()->fastGetAttribute(HTMLNames::typeAttr) : 131 pluginElement->fastGetAttribute(HTMLNames::typeAttr); 132 if (!document()->contentSecurityPolicy()->allowObjectFromSource(url) 133 || !document()->contentSecurityPolicy()->allowPluginType(mimeType, declaredMimeType, url)) { 130 134 RenderEmbeddedObject* renderer = pluginElement->renderEmbeddedObject(); 131 135 renderer->setPluginUnavailabilityReason(RenderEmbeddedObject::PluginBlockedByContentSecurityPolicy); … … 294 298 } 295 299 296 if (!element->document()->contentSecurityPolicy()->allowObjectFromSource(codeBaseURL)) 300 const char javaAppletMimeType[] = "application/x-java-applet"; 301 if (!element->document()->contentSecurityPolicy()->allowObjectFromSource(codeBaseURL) 302 || !element->document()->contentSecurityPolicy()->allowPluginType(javaAppletMimeType, javaAppletMimeType, codeBaseURL)) 297 303 return 0; 298 304 } -
trunk/Source/WebCore/page/ContentSecurityPolicy.cpp
r125213 r125531 41 41 #include "SecurityOrigin.h" 42 42 #include "TextEncoding.h" 43 #include <wtf/HashSet.h> 43 44 #include <wtf/text/TextPosition.h> 44 45 #include <wtf/text/WTFString.h> … … 84 85 { 85 86 return c != ':' && c != '/'; 87 } 88 89 bool isMediaTypeCharacter(UChar c) 90 { 91 return !isASCIISpace(c) && c != '/'; 86 92 } 87 93 … … 562 568 bool allowEval(PassRefPtr<ScriptCallStack>, ContentSecurityPolicy::ReportingStatus) const; 563 569 bool allowScriptNonce(const String& nonce, const String& contextURL, const WTF::OrdinalNumber& contextLine, const KURL&) const; 570 bool allowPluginType(const String& type, const String& typeAttribute, const KURL&, ContentSecurityPolicy::ReportingStatus) const; 564 571 565 572 bool allowScriptFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const; … … 582 589 void parseReportURI(const String& name, const String& value); 583 590 void parseScriptNonce(const String& name, const String& value); 591 void parsePluginTypes(const String& name, const String& value); 584 592 void addDirective(const String& name, const String& value); 585 593 void applySandboxPolicy(const String& name, const String& sandboxPolicy); … … 594 602 bool checkNonce(const String&) const; 595 603 bool checkSource(CSPDirective*, const KURL&) const; 604 bool checkPluginType(const String& type, const String& typeAttribute) const; 596 605 597 606 bool checkEvalAndReportViolation(CSPDirective*, const String& consoleMessage, const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst(), PassRefPtr<ScriptCallStack> = 0) const; … … 599 608 bool checkNonceAndReportViolation(const String& nonce, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine) const; 600 609 bool checkSourceAndReportViolation(CSPDirective*, const KURL&, const String& type) const; 610 bool checkPluginTypeAndReportViolation(const String& type, const String& typeAttribute, const String& consoleMessage) const; 601 611 602 612 bool denyIfEnforcingPolicy() const { return m_reportOnly; } … … 619 629 620 630 Vector<KURL> m_reportURIs; 631 HashSet<String> m_pluginTypes; 632 String m_pluginTypesDirective; 621 633 String m_scriptNonce; 622 634 }; … … 675 687 } 676 688 689 bool CSPDirectiveList::checkPluginType(const String& type, const String& typeAttribute) const 690 { 691 if (m_pluginTypesDirective.isNull()) 692 return true; 693 if (typeAttribute.isEmpty() || typeAttribute.stripWhiteSpace() != type) 694 return false; 695 return m_pluginTypes.contains(type); 696 } 697 677 698 CSPDirective* CSPDirectiveList::operativeDirective(CSPDirective* directive) const 678 699 { … … 693 714 return true; 694 715 reportViolation(m_scriptNonce, consoleMessage + "\"script-nonce " + m_scriptNonce + "\".\n", KURL(), contextURL, contextLine); 716 return denyIfEnforcingPolicy(); 717 } 718 719 bool CSPDirectiveList::checkPluginTypeAndReportViolation(const String& type, const String& typeAttribute, const String& consoleMessage) const 720 { 721 if (checkPluginType(type, typeAttribute)) 722 return true; 723 724 reportViolation(m_pluginTypesDirective, consoleMessage + "'plugin-types " + m_pluginTypesDirective + "'.\n", KURL()); 695 725 return denyIfEnforcingPolicy(); 696 726 } … … 767 797 return checkNonceAndReportViolation(nonce, consoleMessage, contextURL, contextLine); 768 798 return checkNonceAndReportViolation(nonce, "Refused to load '" + url.string() + "' because it violates the following Content Security Policy directive: ", contextURL, contextLine); 799 } 800 801 bool CSPDirectiveList::allowPluginType(const String& type, const String& typeAttribute, const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const 802 { 803 return reportingStatus == ContentSecurityPolicy::SendReport ? 804 checkPluginTypeAndReportViolation(type, typeAttribute, "Refused to load '" + url.string() + "' (MIME type '" + typeAttribute + "') because it violates the following Content Security Policy Directive: ") : 805 checkPluginType(type, typeAttribute); 769 806 } 770 807 … … 976 1013 } 977 1014 1015 void CSPDirectiveList::parsePluginTypes(const String& name, const String& value) 1016 { 1017 if (!m_pluginTypesDirective.isNull()) { 1018 m_policy->reportDuplicateDirective(name); 1019 return; 1020 } 1021 1022 const UChar* begin = value.characters(); 1023 const UChar* position = begin; 1024 const UChar* end = begin + value.length(); 1025 m_pluginTypesDirective = value; 1026 1027 // 'plugin-types ____;' OR 'plugin-types;' 1028 if (value.isEmpty()) { 1029 m_policy->reportInvalidPluginTypes(value); 1030 m_pluginTypesDirective = ""; 1031 return; 1032 } 1033 1034 while (position < end) { 1035 // _____ OR _____mime1/mime1 1036 // ^ ^ 1037 skipWhile<isASCIISpace>(position, end); 1038 if (position == end) 1039 return; 1040 1041 // mime1/mime1 mime2/mime2 1042 // ^ 1043 begin = position; 1044 if (!skipExactly<isMediaTypeCharacter>(position, end)) { 1045 skipWhile<isNotASCIISpace>(position, end); 1046 m_policy->reportInvalidPluginTypes(String(begin, position - begin)); 1047 continue; 1048 } 1049 skipWhile<isMediaTypeCharacter>(position, end); 1050 1051 // mime1/mime1 mime2/mime2 1052 // ^ 1053 if (!skipExactly(position, end, '/')) { 1054 skipWhile<isNotASCIISpace>(position, end); 1055 m_policy->reportInvalidPluginTypes(String(begin, position - begin)); 1056 continue; 1057 } 1058 1059 // mime1/mime1 mime2/mime2 1060 // ^ 1061 if (!skipExactly<isMediaTypeCharacter>(position, end)) { 1062 skipWhile<isNotASCIISpace>(position, end); 1063 m_policy->reportInvalidPluginTypes(String(begin, position - begin)); 1064 continue; 1065 } 1066 skipWhile<isMediaTypeCharacter>(position, end); 1067 1068 // mime1/mime1 mime2/mime2 OR mime1/mime1 OR mime1/mime1/error 1069 // ^ ^ ^ 1070 if (position < end && isNotASCIISpace(*position)) { 1071 skipWhile<isNotASCIISpace>(position, end); 1072 m_policy->reportInvalidPluginTypes(String(begin, position - begin)); 1073 continue; 1074 } 1075 m_pluginTypes.add(String(begin, position - begin)); 1076 1077 ASSERT(position == end || isASCIISpace(*position)); 1078 } 1079 } 1080 978 1081 void CSPDirectiveList::setCSPDirective(const String& name, const String& value, OwnPtr<CSPDirective>& directive) 979 1082 { … … 999 1102 DEFINE_STATIC_LOCAL(String, defaultSrc, ("default-src")); 1000 1103 DEFINE_STATIC_LOCAL(String, scriptSrc, ("script-src")); 1001 #if ENABLE(CSP_NEXT)1002 DEFINE_STATIC_LOCAL(String, scriptNonce, ("script-nonce"));1003 #endif1004 1104 DEFINE_STATIC_LOCAL(String, objectSrc, ("object-src")); 1005 1105 DEFINE_STATIC_LOCAL(String, frameSrc, ("frame-src")); … … 1011 1111 DEFINE_STATIC_LOCAL(String, sandbox, ("sandbox")); 1012 1112 DEFINE_STATIC_LOCAL(String, reportURI, ("report-uri")); 1113 #if ENABLE(CSP_NEXT) 1114 DEFINE_STATIC_LOCAL(String, scriptNonce, ("script-nonce")); 1115 DEFINE_STATIC_LOCAL(String, pluginTypes, ("plugin-types")); 1116 #endif 1013 1117 1014 1118 ASSERT(!name.isEmpty()); … … 1039 1143 else if (equalIgnoringCase(name, scriptNonce)) 1040 1144 parseScriptNonce(name, value); 1145 else if (equalIgnoringCase(name, pluginTypes)) 1146 parsePluginTypes(name, value); 1041 1147 #endif 1042 1148 else … … 1174 1280 { 1175 1281 return isAllowedByAllWithNonce<&CSPDirectiveList::allowScriptNonce>(m_policies, nonce, contextURL, contextLine, url); 1282 } 1283 1284 bool ContentSecurityPolicy::allowPluginType(const String& type, const String& typeAttribute, const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const 1285 { 1286 for (size_t i = 0; i < m_policies.size(); ++i) { 1287 if (!m_policies[i].get()->allowPluginType(type, typeAttribute, url, reportingStatus)) 1288 return false; 1289 } 1290 return true; 1176 1291 } 1177 1292 … … 1305 1420 } 1306 1421 1422 void ContentSecurityPolicy::reportInvalidPluginTypes(const String& pluginType) const 1423 { 1424 String message; 1425 if (pluginType.isNull()) 1426 message = "'plugin-types' Content Security Policy directive is empty; all plugins will be blocked.\n"; 1427 else 1428 message = makeString("Invalid plugin type in 'plugin-types' Content Security Policy directive: '", pluginType, "'.\n"); 1429 logToConsole(message); 1430 } 1431 1307 1432 void ContentSecurityPolicy::reportInvalidNonce(const String& nonce) const 1308 1433 { -
trunk/Source/WebCore/page/ContentSecurityPolicy.h
r125213 r125531 82 82 bool allowEval(PassRefPtr<ScriptCallStack>, ReportingStatus = SendReport) const; 83 83 bool allowScriptNonce(const String& nonce, const String& contextURL, const WTF::OrdinalNumber& contextLine, const KURL& = KURL()) const; 84 bool allowPluginType(const String& type, const String& typeAttribute, const KURL&, ReportingStatus = SendReport) const; 84 85 85 86 bool allowScriptFromSource(const KURL&, ReportingStatus = SendReport) const; … … 100 101 void reportIgnoredPathComponent(const String& directiveName, const String& completeSource, const String& path) const; 101 102 void reportInvalidNonce(const String&) const; 103 void reportInvalidPluginTypes(const String&) const; 102 104 void reportInvalidSourceExpression(const String& directiveName, const String& source) const; 103 105 void reportUnrecognizedDirective(const String&) const;
Note: See TracChangeset
for help on using the changeset viewer.