| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2011 Google, Inc. All rights reserved. | 2 * Copyright (C) 2011 Google, Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 412 bool isAllowed = true; | 412 bool isAllowed = true; |
| 413 for (const auto& policy : policies) | 413 for (const auto& policy : policies) |
| 414 isAllowed &= | 414 isAllowed &= |
| 415 (policy.get()->*allowed)(scriptState, reportingStatus, exceptionStatus); | 415 (policy.get()->*allowed)(scriptState, reportingStatus, exceptionStatus); |
| 416 return isAllowed; | 416 return isAllowed; |
| 417 } | 417 } |
| 418 | 418 |
| 419 template <bool (CSPDirectiveList::*allowed)( | 419 template <bool (CSPDirectiveList::*allowed)( |
| 420 Element*, | 420 Element*, |
| 421 const String&, | 421 const String&, |
| 422 const String&, |
| 422 const WTF::OrdinalNumber&, | 423 const WTF::OrdinalNumber&, |
| 423 ContentSecurityPolicy::ReportingStatus) const> | 424 ContentSecurityPolicy::ReportingStatus) const> |
| 424 bool isAllowedByAll(const CSPDirectiveListVector& policies, | 425 bool isAllowedByAll(const CSPDirectiveListVector& policies, |
| 425 Element* element, | 426 Element* element, |
| 427 const String& source, |
| 426 const String& contextURL, | 428 const String& contextURL, |
| 427 const WTF::OrdinalNumber& contextLine, | 429 const WTF::OrdinalNumber& contextLine, |
| 428 ContentSecurityPolicy::ReportingStatus reportingStatus) { | 430 ContentSecurityPolicy::ReportingStatus reportingStatus) { |
| 429 bool isAllowed = true; | 431 bool isAllowed = true; |
| 430 for (const auto& policy : policies) { | 432 for (const auto& policy : policies) { |
| 431 isAllowed &= (policy.get()->*allowed)(element, contextURL, contextLine, | 433 isAllowed &= (policy.get()->*allowed)(element, source, contextURL, |
| 432 reportingStatus); | 434 contextLine, reportingStatus); |
| 433 } | 435 } |
| 434 return isAllowed; | 436 return isAllowed; |
| 435 } | 437 } |
| 436 | 438 |
| 437 template < | 439 template < |
| 438 bool (CSPDirectiveList::*allowed)(Element*, | 440 bool (CSPDirectiveList::*allowed)(Element*, |
| 439 const String&, | 441 const String&, |
| 440 const String&, | 442 const String&, |
| 441 const WTF::OrdinalNumber&, | 443 const WTF::OrdinalNumber&, |
| 442 ContentSecurityPolicy::ReportingStatus, | 444 ContentSecurityPolicy::ReportingStatus, |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 615 type)) | 617 type)) |
| 616 return true; | 618 return true; |
| 617 } | 619 } |
| 618 } | 620 } |
| 619 | 621 |
| 620 return false; | 622 return false; |
| 621 } | 623 } |
| 622 | 624 |
| 623 bool ContentSecurityPolicy::allowJavaScriptURLs( | 625 bool ContentSecurityPolicy::allowJavaScriptURLs( |
| 624 Element* element, | 626 Element* element, |
| 627 const String& source, |
| 625 const String& contextURL, | 628 const String& contextURL, |
| 626 const WTF::OrdinalNumber& contextLine, | 629 const WTF::OrdinalNumber& contextLine, |
| 627 ContentSecurityPolicy::ReportingStatus reportingStatus) const { | 630 ContentSecurityPolicy::ReportingStatus reportingStatus) const { |
| 628 return isAllowedByAll<&CSPDirectiveList::allowJavaScriptURLs>( | 631 return isAllowedByAll<&CSPDirectiveList::allowJavaScriptURLs>( |
| 629 m_policies, element, contextURL, contextLine, reportingStatus); | 632 m_policies, element, source, contextURL, contextLine, reportingStatus); |
| 630 } | 633 } |
| 631 | 634 |
| 632 bool ContentSecurityPolicy::allowInlineEventHandler( | 635 bool ContentSecurityPolicy::allowInlineEventHandler( |
| 633 Element* element, | 636 Element* element, |
| 634 const String& source, | 637 const String& source, |
| 635 const String& contextURL, | 638 const String& contextURL, |
| 636 const WTF::OrdinalNumber& contextLine, | 639 const WTF::OrdinalNumber& contextLine, |
| 637 ContentSecurityPolicy::ReportingStatus reportingStatus) const { | 640 ContentSecurityPolicy::ReportingStatus reportingStatus) const { |
| 638 // Inline event handlers may be whitelisted by hash, if | 641 // Inline event handlers may be whitelisted by hash, if |
| 639 // 'unsafe-hash-attributes' is present in a policy. Check against the digest | 642 // 'unsafe-hash-attributes' is present in a policy. Check against the digest |
| 640 // of the |source| first before proceeding on to checking whether inline | 643 // of the |source| first before proceeding on to checking whether inline |
| 641 // script is allowed. | 644 // script is allowed. |
| 642 if (checkDigest<&CSPDirectiveList::allowScriptHash>( | 645 if (checkDigest<&CSPDirectiveList::allowScriptHash>( |
| 643 source, InlineType::Attribute, m_scriptHashAlgorithmsUsed, | 646 source, InlineType::Attribute, m_scriptHashAlgorithmsUsed, |
| 644 m_policies)) | 647 m_policies)) |
| 645 return true; | 648 return true; |
| 646 return isAllowedByAll<&CSPDirectiveList::allowInlineEventHandlers>( | 649 return isAllowedByAll<&CSPDirectiveList::allowInlineEventHandlers>( |
| 647 m_policies, element, contextURL, contextLine, reportingStatus); | 650 m_policies, element, source, contextURL, contextLine, reportingStatus); |
| 648 } | 651 } |
| 649 | 652 |
| 650 bool ContentSecurityPolicy::allowInlineScript( | 653 bool ContentSecurityPolicy::allowInlineScript( |
| 651 Element* element, | 654 Element* element, |
| 652 const String& contextURL, | 655 const String& contextURL, |
| 653 const String& nonce, | 656 const String& nonce, |
| 654 const WTF::OrdinalNumber& contextLine, | 657 const WTF::OrdinalNumber& contextLine, |
| 655 const String& scriptContent, | 658 const String& scriptContent, |
| 656 ContentSecurityPolicy::ReportingStatus reportingStatus) const { | 659 ContentSecurityPolicy::ReportingStatus reportingStatus) const { |
| 657 DCHECK(element); | 660 DCHECK(element); |
| (...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1036 static void gatherSecurityPolicyViolationEventData( | 1039 static void gatherSecurityPolicyViolationEventData( |
| 1037 SecurityPolicyViolationEventInit& init, | 1040 SecurityPolicyViolationEventInit& init, |
| 1038 ExecutionContext* context, | 1041 ExecutionContext* context, |
| 1039 const String& directiveText, | 1042 const String& directiveText, |
| 1040 const ContentSecurityPolicy::DirectiveType& effectiveType, | 1043 const ContentSecurityPolicy::DirectiveType& effectiveType, |
| 1041 const KURL& blockedURL, | 1044 const KURL& blockedURL, |
| 1042 const String& header, | 1045 const String& header, |
| 1043 RedirectStatus redirectStatus, | 1046 RedirectStatus redirectStatus, |
| 1044 ContentSecurityPolicyHeaderType headerType, | 1047 ContentSecurityPolicyHeaderType headerType, |
| 1045 ContentSecurityPolicy::ViolationType violationType, | 1048 ContentSecurityPolicy::ViolationType violationType, |
| 1046 int contextLine) { | 1049 int contextLine, |
| 1050 const String& scriptSource) { |
| 1047 if (effectiveType == ContentSecurityPolicy::DirectiveType::FrameAncestors) { | 1051 if (effectiveType == ContentSecurityPolicy::DirectiveType::FrameAncestors) { |
| 1048 // If this load was blocked via 'frame-ancestors', then the URL of | 1052 // If this load was blocked via 'frame-ancestors', then the URL of |
| 1049 // |document| has not yet been initialized. In this case, we'll set both | 1053 // |document| has not yet been initialized. In this case, we'll set both |
| 1050 // 'documentURI' and 'blockedURI' to the blocked document's URL. | 1054 // 'documentURI' and 'blockedURI' to the blocked document's URL. |
| 1051 init.setDocumentURI(blockedURL.getString()); | 1055 init.setDocumentURI(blockedURL.getString()); |
| 1052 init.setBlockedURI(blockedURL.getString()); | 1056 init.setBlockedURI(blockedURL.getString()); |
| 1053 } else { | 1057 } else { |
| 1054 init.setDocumentURI(context->url().getString()); | 1058 init.setDocumentURI(context->url().getString()); |
| 1055 switch (violationType) { | 1059 switch (violationType) { |
| 1056 case ContentSecurityPolicy::InlineViolation: | 1060 case ContentSecurityPolicy::InlineViolation: |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1090 } | 1094 } |
| 1091 | 1095 |
| 1092 std::unique_ptr<SourceLocation> location = SourceLocation::capture(context); | 1096 std::unique_ptr<SourceLocation> location = SourceLocation::capture(context); |
| 1093 if (location->lineNumber()) { | 1097 if (location->lineNumber()) { |
| 1094 KURL source = KURL(ParsedURLString, location->url()); | 1098 KURL source = KURL(ParsedURLString, location->url()); |
| 1095 init.setSourceFile( | 1099 init.setSourceFile( |
| 1096 stripURLForUseInReport(context, source, redirectStatus, effectiveType)); | 1100 stripURLForUseInReport(context, source, redirectStatus, effectiveType)); |
| 1097 init.setLineNumber(location->lineNumber()); | 1101 init.setLineNumber(location->lineNumber()); |
| 1098 init.setColumnNumber(location->columnNumber()); | 1102 init.setColumnNumber(location->columnNumber()); |
| 1099 } | 1103 } |
| 1104 |
| 1105 if (!scriptSource.isEmpty()) |
| 1106 init.setScriptSample(scriptSource.stripWhiteSpace().left(40)); |
| 1100 } | 1107 } |
| 1101 | 1108 |
| 1102 void ContentSecurityPolicy::reportViolation( | 1109 void ContentSecurityPolicy::reportViolation( |
| 1103 const String& directiveText, | 1110 const String& directiveText, |
| 1104 const DirectiveType& effectiveType, | 1111 const DirectiveType& effectiveType, |
| 1105 const String& consoleMessage, | 1112 const String& consoleMessage, |
| 1106 const KURL& blockedURL, | 1113 const KURL& blockedURL, |
| 1107 const Vector<String>& reportEndpoints, | 1114 const Vector<String>& reportEndpoints, |
| 1108 const String& header, | 1115 const String& header, |
| 1109 ContentSecurityPolicyHeaderType headerType, | 1116 ContentSecurityPolicyHeaderType headerType, |
| 1110 ViolationType violationType, | 1117 ViolationType violationType, |
| 1111 LocalFrame* contextFrame, | 1118 LocalFrame* contextFrame, |
| 1112 RedirectStatus redirectStatus, | 1119 RedirectStatus redirectStatus, |
| 1113 int contextLine, | 1120 int contextLine, |
| 1114 Element* element) { | 1121 Element* element, |
| 1122 const String& source) { |
| 1115 ASSERT(violationType == URLViolation || blockedURL.isEmpty()); | 1123 ASSERT(violationType == URLViolation || blockedURL.isEmpty()); |
| 1116 | 1124 |
| 1117 // TODO(lukasza): Support sending reports from OOPIFs - | 1125 // TODO(lukasza): Support sending reports from OOPIFs - |
| 1118 // https://crbug.com/611232 (or move CSP child-src and frame-src checks to the | 1126 // https://crbug.com/611232 (or move CSP child-src and frame-src checks to the |
| 1119 // browser process - see https://crbug.com/376522). | 1127 // browser process - see https://crbug.com/376522). |
| 1120 if (!m_executionContext && !contextFrame) { | 1128 if (!m_executionContext && !contextFrame) { |
| 1121 DCHECK(effectiveType == DirectiveType::ChildSrc || | 1129 DCHECK(effectiveType == DirectiveType::ChildSrc || |
| 1122 effectiveType == DirectiveType::FrameSrc || | 1130 effectiveType == DirectiveType::FrameSrc || |
| 1123 effectiveType == DirectiveType::PluginTypes); | 1131 effectiveType == DirectiveType::PluginTypes); |
| 1124 return; | 1132 return; |
| 1125 } | 1133 } |
| 1126 | 1134 |
| 1127 DCHECK((m_executionContext && !contextFrame) || | 1135 DCHECK((m_executionContext && !contextFrame) || |
| 1128 ((effectiveType == DirectiveType::FrameAncestors) && contextFrame)); | 1136 ((effectiveType == DirectiveType::FrameAncestors) && contextFrame)); |
| 1129 | 1137 |
| 1130 SecurityPolicyViolationEventInit violationData; | 1138 SecurityPolicyViolationEventInit violationData; |
| 1131 | 1139 |
| 1132 // If we're processing 'frame-ancestors', use |contextFrame|'s execution | 1140 // If we're processing 'frame-ancestors', use |contextFrame|'s execution |
| 1133 // context to gather data. Otherwise, use the policy's execution context. | 1141 // context to gather data. Otherwise, use the policy's execution context. |
| 1134 ExecutionContext* relevantContext = | 1142 ExecutionContext* relevantContext = |
| 1135 contextFrame ? contextFrame->document() : m_executionContext; | 1143 contextFrame ? contextFrame->document() : m_executionContext; |
| 1136 DCHECK(relevantContext); | 1144 DCHECK(relevantContext); |
| 1137 gatherSecurityPolicyViolationEventData( | 1145 gatherSecurityPolicyViolationEventData( |
| 1138 violationData, relevantContext, directiveText, effectiveType, blockedURL, | 1146 violationData, relevantContext, directiveText, effectiveType, blockedURL, |
| 1139 header, redirectStatus, headerType, violationType, contextLine); | 1147 header, redirectStatus, headerType, violationType, contextLine, source); |
| 1140 | 1148 |
| 1141 // TODO(mkwst): Obviously, we shouldn't hit this check, as extension-loaded | 1149 // TODO(mkwst): Obviously, we shouldn't hit this check, as extension-loaded |
| 1142 // resources should be allowed regardless. We apparently do, however, so | 1150 // resources should be allowed regardless. We apparently do, however, so |
| 1143 // we should at least stop spamming reporting endpoints. See | 1151 // we should at least stop spamming reporting endpoints. See |
| 1144 // https://crbug.com/524356 for detail. | 1152 // https://crbug.com/524356 for detail. |
| 1145 if (!violationData.sourceFile().isEmpty() && | 1153 if (!violationData.sourceFile().isEmpty() && |
| 1146 SchemeRegistry::schemeShouldBypassContentSecurityPolicy( | 1154 SchemeRegistry::schemeShouldBypassContentSecurityPolicy( |
| 1147 KURL(ParsedURLString, violationData.sourceFile()).protocol())) { | 1155 KURL(ParsedURLString, violationData.sourceFile()).protocol())) { |
| 1148 return; | 1156 return; |
| 1149 } | 1157 } |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1191 cspReport->setString("disposition", violationData.disposition()); | 1199 cspReport->setString("disposition", violationData.disposition()); |
| 1192 cspReport->setString("blocked-uri", violationData.blockedURI()); | 1200 cspReport->setString("blocked-uri", violationData.blockedURI()); |
| 1193 if (violationData.lineNumber()) | 1201 if (violationData.lineNumber()) |
| 1194 cspReport->setInteger("line-number", violationData.lineNumber()); | 1202 cspReport->setInteger("line-number", violationData.lineNumber()); |
| 1195 if (violationData.columnNumber()) | 1203 if (violationData.columnNumber()) |
| 1196 cspReport->setInteger("column-number", violationData.columnNumber()); | 1204 cspReport->setInteger("column-number", violationData.columnNumber()); |
| 1197 if (!violationData.sourceFile().isEmpty()) | 1205 if (!violationData.sourceFile().isEmpty()) |
| 1198 cspReport->setString("source-file", violationData.sourceFile()); | 1206 cspReport->setString("source-file", violationData.sourceFile()); |
| 1199 cspReport->setInteger("status-code", violationData.statusCode()); | 1207 cspReport->setInteger("status-code", violationData.statusCode()); |
| 1200 | 1208 |
| 1209 if (experimentalFeaturesEnabled()) |
| 1210 cspReport->setString("script-sample", violationData.scriptSample()); |
| 1211 |
| 1201 std::unique_ptr<JSONObject> reportObject = JSONObject::create(); | 1212 std::unique_ptr<JSONObject> reportObject = JSONObject::create(); |
| 1202 reportObject->setObject("csp-report", std::move(cspReport)); | 1213 reportObject->setObject("csp-report", std::move(cspReport)); |
| 1203 String stringifiedReport = reportObject->toJSONString(); | 1214 String stringifiedReport = reportObject->toJSONString(); |
| 1204 | 1215 |
| 1205 // Only POST unique reports to the external endpoint; repeated reports add no | 1216 // Only POST unique reports to the external endpoint; repeated reports add no |
| 1206 // value on the server side, as they're indistinguishable. Note that we'll | 1217 // value on the server side, as they're indistinguishable. Note that we'll |
| 1207 // fire the DOM event for every violation, as the page has enough context to | 1218 // fire the DOM event for every violation, as the page has enough context to |
| 1208 // react in some reasonable way to each violation as it occurs. | 1219 // react in some reasonable way to each violation as it occurs. |
| 1209 if (shouldSendViolationReport(stringifiedReport)) { | 1220 if (shouldSendViolationReport(stringifiedReport)) { |
| 1210 didSendViolationReport(stringifiedReport); | 1221 didSendViolationReport(stringifiedReport); |
| (...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1628 CSPDirectiveListVector otherVector; | 1639 CSPDirectiveListVector otherVector; |
| 1629 for (const auto& policy : other.m_policies) { | 1640 for (const auto& policy : other.m_policies) { |
| 1630 if (!policy->isReportOnly()) | 1641 if (!policy->isReportOnly()) |
| 1631 otherVector.push_back(policy); | 1642 otherVector.push_back(policy); |
| 1632 } | 1643 } |
| 1633 | 1644 |
| 1634 return m_policies[0]->subsumes(otherVector); | 1645 return m_policies[0]->subsumes(otherVector); |
| 1635 } | 1646 } |
| 1636 | 1647 |
| 1637 } // namespace blink | 1648 } // namespace blink |
| OLD | NEW |