OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/frame/csp/CSPDirectiveList.h" | 5 #include "core/frame/csp/CSPDirectiveList.h" |
6 | 6 |
7 #include "bindings/core/v8/SourceLocation.h" | 7 #include "bindings/core/v8/SourceLocation.h" |
8 #include "core/dom/Document.h" | 8 #include "core/dom/Document.h" |
9 #include "core/dom/SecurityContext.h" | 9 #include "core/dom/SecurityContext.h" |
10 #include "core/dom/SpaceSplitString.h" | 10 #include "core/dom/SpaceSplitString.h" |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 , m_headerType(type) | 48 , m_headerType(type) |
49 , m_headerSource(source) | 49 , m_headerSource(source) |
50 , m_reportOnly(false) | 50 , m_reportOnly(false) |
51 , m_hasSandboxPolicy(false) | 51 , m_hasSandboxPolicy(false) |
52 , m_reflectedXSSDisposition(ReflectedXSSUnset) | 52 , m_reflectedXSSDisposition(ReflectedXSSUnset) |
53 , m_didSetReferrerPolicy(false) | 53 , m_didSetReferrerPolicy(false) |
54 , m_referrerPolicy(ReferrerPolicyDefault) | 54 , m_referrerPolicy(ReferrerPolicyDefault) |
55 , m_strictMixedContentCheckingEnforced(false) | 55 , m_strictMixedContentCheckingEnforced(false) |
56 , m_upgradeInsecureRequests(false) | 56 , m_upgradeInsecureRequests(false) |
57 , m_treatAsPublicAddress(false) | 57 , m_treatAsPublicAddress(false) |
| 58 , m_requireSRIFor(RequireSRIForToken::None) |
58 { | 59 { |
59 m_reportOnly = type == ContentSecurityPolicyHeaderTypeReport; | 60 m_reportOnly = type == ContentSecurityPolicyHeaderTypeReport; |
60 } | 61 } |
61 | 62 |
62 CSPDirectiveList* CSPDirectiveList::create(ContentSecurityPolicy* policy, const
UChar* begin, const UChar* end, ContentSecurityPolicyHeaderType type, ContentSec
urityPolicyHeaderSource source) | 63 CSPDirectiveList* CSPDirectiveList::create(ContentSecurityPolicy* policy, const
UChar* begin, const UChar* end, ContentSecurityPolicyHeaderType type, ContentSec
urityPolicyHeaderSource source) |
63 { | 64 { |
64 CSPDirectiveList* directives = new CSPDirectiveList(policy, type, source); | 65 CSPDirectiveList* directives = new CSPDirectiveList(policy, type, source); |
65 directives->parse(begin, end); | 66 directives->parse(begin, end); |
66 | 67 |
67 if (!directives->checkEval(directives->operativeDirective(directives->m_scri
ptSrc.get()))) { | 68 if (!directives->checkEval(directives->operativeDirective(directives->m_scri
ptSrc.get()))) { |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 // | 167 // |
167 // TODO(mkwst): Move this check up into the browser process. See | 168 // TODO(mkwst): Move this check up into the browser process. See |
168 // https://crbug.com/555418. | 169 // https://crbug.com/555418. |
169 KURL url(KURL(), current->securityContext()->getSecurityOrigin()->toStri
ng()); | 170 KURL url(KURL(), current->securityContext()->getSecurityOrigin()->toStri
ng()); |
170 if (!directive->allows(url, ResourceRequest::RedirectStatus::NoRedirect)
) | 171 if (!directive->allows(url, ResourceRequest::RedirectStatus::NoRedirect)
) |
171 return false; | 172 return false; |
172 } | 173 } |
173 return true; | 174 return true; |
174 } | 175 } |
175 | 176 |
| 177 bool CSPDirectiveList::checkRequestWithoutIntegrity(WebURLRequest::RequestContex
t context) const |
| 178 { |
| 179 if (m_requireSRIFor == RequireSRIForToken::None) |
| 180 return true; |
| 181 // SRI specification (https://w3c.github.io/webappsec-subresource-integrity/
#apply-algorithm-to-request) |
| 182 // says to match token with request's destination with the token. |
| 183 // Keep this logic aligned with ContentSecurityPolicy::allowRequest |
| 184 if ((m_requireSRIFor & RequireSRIForToken::Script) |
| 185 && (context == WebURLRequest::RequestContextScript |
| 186 || context == WebURLRequest::RequestContextImport |
| 187 || context == WebURLRequest::RequestContextServiceWorker |
| 188 || context == WebURLRequest::RequestContextSharedWorker |
| 189 || context == WebURLRequest::RequestContextWorker)) { |
| 190 return false; |
| 191 } |
| 192 if ((m_requireSRIFor & RequireSRIForToken::Style) && context == WebURLReques
t::RequestContextStyle) |
| 193 return false; |
| 194 return true; |
| 195 } |
| 196 |
| 197 bool CSPDirectiveList::checkRequestWithoutIntegrityAndReportViolation(WebURLRequ
est::RequestContext context, const KURL& url, ResourceRequest::RedirectStatus re
directStatus) const |
| 198 { |
| 199 if (checkRequestWithoutIntegrity(context)) |
| 200 return true; |
| 201 String resourceType; |
| 202 switch (context) { |
| 203 case WebURLRequest::RequestContextScript: |
| 204 case WebURLRequest::RequestContextImport: |
| 205 resourceType = "script"; |
| 206 break; |
| 207 case WebURLRequest::RequestContextStyle: |
| 208 resourceType = "stylesheet"; |
| 209 break; |
| 210 case WebURLRequest::RequestContextServiceWorker: |
| 211 resourceType = "service worker"; |
| 212 break; |
| 213 case WebURLRequest::RequestContextSharedWorker: |
| 214 resourceType = "shared worker"; |
| 215 break; |
| 216 case WebURLRequest::RequestContextWorker: |
| 217 resourceType = "worker"; |
| 218 break; |
| 219 default: |
| 220 break; |
| 221 } |
| 222 |
| 223 reportViolation(ContentSecurityPolicy::RequireSRIFor, ContentSecurityPolicy:
:RequireSRIFor, "Refused to load the " + resourceType + " '" + url.elidedString(
) + "' because 'require-sri-for' directive requires integrity attribute be prese
nt for all " + resourceType + "s.", url, redirectStatus); |
| 224 return denyIfEnforcingPolicy(); |
| 225 } |
| 226 |
| 227 bool CSPDirectiveList::allowRequestWithoutIntegrity(WebURLRequest::RequestContex
t context, const KURL& url, ResourceRequest::RedirectStatus redirectStatus, Cont
entSecurityPolicy::ReportingStatus reportingStatus) const |
| 228 { |
| 229 if (reportingStatus == ContentSecurityPolicy::SendReport) |
| 230 return checkRequestWithoutIntegrityAndReportViolation(context, url, redi
rectStatus); |
| 231 return denyIfEnforcingPolicy() || checkRequestWithoutIntegrity(context); |
| 232 } |
| 233 |
176 bool CSPDirectiveList::checkMediaType(MediaListDirective* directive, const Strin
g& type, const String& typeAttribute) const | 234 bool CSPDirectiveList::checkMediaType(MediaListDirective* directive, const Strin
g& type, const String& typeAttribute) const |
177 { | 235 { |
178 if (!directive) | 236 if (!directive) |
179 return true; | 237 return true; |
180 if (typeAttribute.isEmpty() || typeAttribute.stripWhiteSpace() != type) | 238 if (typeAttribute.isEmpty() || typeAttribute.stripWhiteSpace() != type) |
181 return false; | 239 return false; |
182 return directive->allows(type); | 240 return directive->allows(type); |
183 } | 241 } |
184 | 242 |
185 SourceListDirective* CSPDirectiveList::operativeDirective(SourceListDirective* d
irective) const | 243 SourceListDirective* CSPDirectiveList::operativeDirective(SourceListDirective* d
irective) const |
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
544 } | 602 } |
545 | 603 |
546 // The directive-value may be empty. | 604 // The directive-value may be empty. |
547 if (valueBegin == position) | 605 if (valueBegin == position) |
548 return true; | 606 return true; |
549 | 607 |
550 value = String(valueBegin, position - valueBegin); | 608 value = String(valueBegin, position - valueBegin); |
551 return true; | 609 return true; |
552 } | 610 } |
553 | 611 |
| 612 void CSPDirectiveList::parseRequireSRIFor(const String& name, const String& valu
e) |
| 613 { |
| 614 if (m_requireSRIFor != 0) { |
| 615 m_policy->reportDuplicateDirective(name); |
| 616 return; |
| 617 } |
| 618 StringBuilder tokenErrors; |
| 619 unsigned numberOfTokenErrors = 0; |
| 620 Vector<UChar> characters; |
| 621 value.appendTo(characters); |
| 622 |
| 623 const UChar* position = characters.data(); |
| 624 const UChar* end = position + characters.size(); |
| 625 |
| 626 while (position < end) { |
| 627 skipWhile<UChar, isASCIISpace>(position, end); |
| 628 |
| 629 const UChar* tokenBegin = position; |
| 630 skipWhile<UChar, isNotASCIISpace>(position, end); |
| 631 |
| 632 if (tokenBegin < position) { |
| 633 String token = String(tokenBegin, position - tokenBegin); |
| 634 if (equalIgnoringCase(token, "script")) { |
| 635 m_requireSRIFor |= RequireSRIForToken::Script; |
| 636 } else if (equalIgnoringCase(token, "style")) { |
| 637 m_requireSRIFor |= RequireSRIForToken::Style; |
| 638 } else { |
| 639 if (numberOfTokenErrors) |
| 640 tokenErrors.append(", \'"); |
| 641 else |
| 642 tokenErrors.append('\''); |
| 643 tokenErrors.append(token); |
| 644 tokenErrors.append('\''); |
| 645 numberOfTokenErrors++; |
| 646 } |
| 647 } |
| 648 } |
| 649 |
| 650 if (numberOfTokenErrors == 0) |
| 651 return; |
| 652 |
| 653 String invalidTokensErrorMessage; |
| 654 if (numberOfTokenErrors > 1) |
| 655 tokenErrors.append(" are invalid 'require-sri-for' tokens."); |
| 656 else |
| 657 tokenErrors.append(" is an invalid 'require-sri-for' token."); |
| 658 |
| 659 invalidTokensErrorMessage = tokenErrors.toString(); |
| 660 |
| 661 DCHECK(!invalidTokensErrorMessage.isEmpty()); |
| 662 |
| 663 m_policy->reportInvalidRequireSRIForTokens(invalidTokensErrorMessage); |
| 664 } |
| 665 |
554 void CSPDirectiveList::parseReportURI(const String& name, const String& value) | 666 void CSPDirectiveList::parseReportURI(const String& name, const String& value) |
555 { | 667 { |
556 if (!m_reportEndpoints.isEmpty()) { | 668 if (!m_reportEndpoints.isEmpty()) { |
557 m_policy->reportDuplicateDirective(name); | 669 m_policy->reportDuplicateDirective(name); |
558 return; | 670 return; |
559 } | 671 } |
560 | 672 |
561 // Remove report-uri in meta policies, per https://www.w3.org/TR/CSP2/#deliv
ery-html-meta-element. | 673 // Remove report-uri in meta policies, per https://www.w3.org/TR/CSP2/#deliv
ery-html-meta-element. |
562 if (m_headerSource == ContentSecurityPolicyHeaderSourceMeta) { | 674 if (m_headerSource == ContentSecurityPolicyHeaderSourceMeta) { |
563 UseCounter::count(m_policy->document(), UseCounter::InvalidReportUriDire
ctiveInMetaCSP); | 675 UseCounter::count(m_policy->document(), UseCounter::InvalidReportUriDire
ctiveInMetaCSP); |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
817 } else if (equalIgnoringCase(name, ContentSecurityPolicy::Referrer)) { | 929 } else if (equalIgnoringCase(name, ContentSecurityPolicy::Referrer)) { |
818 parseReferrer(name, value); | 930 parseReferrer(name, value); |
819 } else if (equalIgnoringCase(name, ContentSecurityPolicy::UpgradeInsecureReq
uests)) { | 931 } else if (equalIgnoringCase(name, ContentSecurityPolicy::UpgradeInsecureReq
uests)) { |
820 enableInsecureRequestsUpgrade(name, value); | 932 enableInsecureRequestsUpgrade(name, value); |
821 } else if (equalIgnoringCase(name, ContentSecurityPolicy::BlockAllMixedConte
nt)) { | 933 } else if (equalIgnoringCase(name, ContentSecurityPolicy::BlockAllMixedConte
nt)) { |
822 enforceStrictMixedContentChecking(name, value); | 934 enforceStrictMixedContentChecking(name, value); |
823 } else if (equalIgnoringCase(name, ContentSecurityPolicy::ManifestSrc)) { | 935 } else if (equalIgnoringCase(name, ContentSecurityPolicy::ManifestSrc)) { |
824 setCSPDirective<SourceListDirective>(name, value, m_manifestSrc); | 936 setCSPDirective<SourceListDirective>(name, value, m_manifestSrc); |
825 } else if (equalIgnoringCase(name, ContentSecurityPolicy::TreatAsPublicAddre
ss)) { | 937 } else if (equalIgnoringCase(name, ContentSecurityPolicy::TreatAsPublicAddre
ss)) { |
826 treatAsPublicAddress(name, value); | 938 treatAsPublicAddress(name, value); |
| 939 } else if (equalIgnoringCase(name, ContentSecurityPolicy::RequireSRIFor) &&
m_policy->experimentalFeaturesEnabled()) { |
| 940 parseRequireSRIFor(name, value); |
827 } else { | 941 } else { |
828 m_policy->reportUnsupportedDirective(name); | 942 m_policy->reportUnsupportedDirective(name); |
829 } | 943 } |
830 } | 944 } |
831 | 945 |
832 DEFINE_TRACE(CSPDirectiveList) | 946 DEFINE_TRACE(CSPDirectiveList) |
833 { | 947 { |
834 visitor->trace(m_policy); | 948 visitor->trace(m_policy); |
835 visitor->trace(m_pluginTypes); | 949 visitor->trace(m_pluginTypes); |
836 visitor->trace(m_baseURI); | 950 visitor->trace(m_baseURI); |
837 visitor->trace(m_childSrc); | 951 visitor->trace(m_childSrc); |
838 visitor->trace(m_connectSrc); | 952 visitor->trace(m_connectSrc); |
839 visitor->trace(m_defaultSrc); | 953 visitor->trace(m_defaultSrc); |
840 visitor->trace(m_fontSrc); | 954 visitor->trace(m_fontSrc); |
841 visitor->trace(m_formAction); | 955 visitor->trace(m_formAction); |
842 visitor->trace(m_frameAncestors); | 956 visitor->trace(m_frameAncestors); |
843 visitor->trace(m_frameSrc); | 957 visitor->trace(m_frameSrc); |
844 visitor->trace(m_imgSrc); | 958 visitor->trace(m_imgSrc); |
845 visitor->trace(m_mediaSrc); | 959 visitor->trace(m_mediaSrc); |
846 visitor->trace(m_manifestSrc); | 960 visitor->trace(m_manifestSrc); |
847 visitor->trace(m_objectSrc); | 961 visitor->trace(m_objectSrc); |
848 visitor->trace(m_scriptSrc); | 962 visitor->trace(m_scriptSrc); |
849 visitor->trace(m_styleSrc); | 963 visitor->trace(m_styleSrc); |
850 } | 964 } |
851 | 965 |
852 | 966 |
853 } // namespace blink | 967 } // namespace blink |
OLD | NEW |