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 |