Chromium Code Reviews| 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(0) | |
| 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 == 0) | |
|
Mike West
2016/06/20 08:11:37
Nit: Prefer `if (!m_requireSRIFor)` or `if (m_requ
Sergey Shekyan
2016/06/21 06:34:51
Acknowledged.
| |
| 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 && (context == WebURLReques t::RequestContextScript || context == WebURLRequest::RequestContextImport)) { | |
| 185 return false; | |
| 186 } | |
| 187 if (m_requireSRIFor & RequireSRIForToken::Style && context == WebURLRequest: :RequestContextStyle) { | |
| 188 return false; | |
| 189 } | |
| 190 return true; | |
| 191 } | |
| 192 | |
| 193 bool CSPDirectiveList::checkRequestWithoutIntegrityAndReportViolation(WebURLRequ est::RequestContext context, const KURL& url, ResourceRequest::RedirectStatus re directStatus) const | |
| 194 { | |
| 195 if (checkRequestWithoutIntegrity(context)) | |
| 196 return true; | |
| 197 String resourceType; | |
| 198 if (context == WebURLRequest::RequestContextScript || context == WebURLReque st::RequestContextImport) | |
| 199 resourceType = "script"; | |
| 200 else if (context == WebURLRequest::RequestContextStyle) | |
| 201 resourceType = "stylesheet"; | |
| 202 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); | |
| 203 return denyIfEnforcingPolicy(); | |
| 204 } | |
| 205 | |
| 206 bool CSPDirectiveList::allowRequestWithoutIntegrity(WebURLRequest::RequestContex t context, const KURL& url, ResourceRequest::RedirectStatus redirectStatus, Cont entSecurityPolicy::ReportingStatus reportingStatus) const | |
| 207 { | |
| 208 if (reportingStatus == ContentSecurityPolicy::SendReport) { | |
| 209 return checkRequestWithoutIntegrityAndReportViolation(context, url, redi rectStatus); | |
| 210 } | |
|
Mike West
2016/06/20 08:11:37
Nit: No {} for single-line bodies.
Sergey Shekyan
2016/06/21 06:34:51
Acknowledged.
| |
| 211 return checkRequestWithoutIntegrity(context); | |
| 212 } | |
| 213 | |
| 176 bool CSPDirectiveList::checkMediaType(MediaListDirective* directive, const Strin g& type, const String& typeAttribute) const | 214 bool CSPDirectiveList::checkMediaType(MediaListDirective* directive, const Strin g& type, const String& typeAttribute) const |
| 177 { | 215 { |
| 178 if (!directive) | 216 if (!directive) |
| 179 return true; | 217 return true; |
| 180 if (typeAttribute.isEmpty() || typeAttribute.stripWhiteSpace() != type) | 218 if (typeAttribute.isEmpty() || typeAttribute.stripWhiteSpace() != type) |
| 181 return false; | 219 return false; |
| 182 return directive->allows(type); | 220 return directive->allows(type); |
| 183 } | 221 } |
| 184 | 222 |
| 185 SourceListDirective* CSPDirectiveList::operativeDirective(SourceListDirective* d irective) const | 223 SourceListDirective* CSPDirectiveList::operativeDirective(SourceListDirective* d irective) const |
| (...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 544 } | 582 } |
| 545 | 583 |
| 546 // The directive-value may be empty. | 584 // The directive-value may be empty. |
| 547 if (valueBegin == position) | 585 if (valueBegin == position) |
| 548 return true; | 586 return true; |
| 549 | 587 |
| 550 value = String(valueBegin, position - valueBegin); | 588 value = String(valueBegin, position - valueBegin); |
| 551 return true; | 589 return true; |
| 552 } | 590 } |
| 553 | 591 |
| 592 void CSPDirectiveList::parseRequireSRIFor(const String& name, const String& valu e) | |
| 593 { | |
| 594 if (m_requireSRIFor != 0) { | |
| 595 m_policy->reportDuplicateDirective(name); | |
| 596 return; | |
| 597 } | |
| 598 StringBuilder tokenErrors; | |
| 599 unsigned numberOfTokenErrors = 0; | |
| 600 Vector<UChar> characters; | |
| 601 value.appendTo(characters); | |
| 602 | |
| 603 const UChar* position = characters.data(); | |
| 604 const UChar* end = position + characters.size(); | |
| 605 | |
| 606 while (position < end) { | |
| 607 skipWhile<UChar, isASCIISpace>(position, end); | |
| 608 | |
| 609 const UChar* tokenBegin = position; | |
| 610 skipWhile<UChar, isNotASCIISpace>(position, end); | |
| 611 | |
| 612 if (tokenBegin < position) { | |
| 613 String token = String(tokenBegin, position - tokenBegin); | |
| 614 if (equalIgnoringCase(token, "script")) { | |
| 615 m_requireSRIFor |= RequireSRIForToken::Script; | |
| 616 } else if (equalIgnoringCase(token, "style")) { | |
| 617 m_requireSRIFor |= RequireSRIForToken::Style; | |
| 618 } else { | |
| 619 if (numberOfTokenErrors) | |
| 620 tokenErrors.append(", \'"); | |
| 621 else | |
| 622 tokenErrors.append('\''); | |
| 623 tokenErrors.append(token); | |
| 624 tokenErrors.append('\''); | |
| 625 numberOfTokenErrors++; | |
| 626 } | |
| 627 } | |
| 628 } | |
| 629 | |
| 630 if (numberOfTokenErrors == 0) | |
| 631 return; | |
| 632 | |
| 633 String invalidTokensErrorMessage; | |
| 634 if (numberOfTokenErrors > 1) | |
| 635 tokenErrors.append(" are invalid 'require-sri-for' tokens."); | |
| 636 else | |
| 637 tokenErrors.append(" is an invalid 'require-sri-for' token."); | |
| 638 | |
| 639 invalidTokensErrorMessage = tokenErrors.toString(); | |
| 640 | |
| 641 DCHECK(!invalidTokensErrorMessage.isEmpty()); | |
| 642 | |
| 643 m_policy->reportInvalidRequireSRIForTokens(invalidTokensErrorMessage); | |
| 644 } | |
| 645 | |
| 554 void CSPDirectiveList::parseReportURI(const String& name, const String& value) | 646 void CSPDirectiveList::parseReportURI(const String& name, const String& value) |
| 555 { | 647 { |
| 556 if (!m_reportEndpoints.isEmpty()) { | 648 if (!m_reportEndpoints.isEmpty()) { |
| 557 m_policy->reportDuplicateDirective(name); | 649 m_policy->reportDuplicateDirective(name); |
| 558 return; | 650 return; |
| 559 } | 651 } |
| 560 | 652 |
| 561 // Remove report-uri in meta policies, per https://www.w3.org/TR/CSP2/#deliv ery-html-meta-element. | 653 // Remove report-uri in meta policies, per https://www.w3.org/TR/CSP2/#deliv ery-html-meta-element. |
| 562 if (m_headerSource == ContentSecurityPolicyHeaderSourceMeta) { | 654 if (m_headerSource == ContentSecurityPolicyHeaderSourceMeta) { |
| 563 UseCounter::count(m_policy->document(), UseCounter::InvalidReportUriDire ctiveInMetaCSP); | 655 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)) { | 909 } else if (equalIgnoringCase(name, ContentSecurityPolicy::Referrer)) { |
| 818 parseReferrer(name, value); | 910 parseReferrer(name, value); |
| 819 } else if (equalIgnoringCase(name, ContentSecurityPolicy::UpgradeInsecureReq uests)) { | 911 } else if (equalIgnoringCase(name, ContentSecurityPolicy::UpgradeInsecureReq uests)) { |
| 820 enableInsecureRequestsUpgrade(name, value); | 912 enableInsecureRequestsUpgrade(name, value); |
| 821 } else if (equalIgnoringCase(name, ContentSecurityPolicy::BlockAllMixedConte nt)) { | 913 } else if (equalIgnoringCase(name, ContentSecurityPolicy::BlockAllMixedConte nt)) { |
| 822 enforceStrictMixedContentChecking(name, value); | 914 enforceStrictMixedContentChecking(name, value); |
| 823 } else if (equalIgnoringCase(name, ContentSecurityPolicy::ManifestSrc)) { | 915 } else if (equalIgnoringCase(name, ContentSecurityPolicy::ManifestSrc)) { |
| 824 setCSPDirective<SourceListDirective>(name, value, m_manifestSrc); | 916 setCSPDirective<SourceListDirective>(name, value, m_manifestSrc); |
| 825 } else if (equalIgnoringCase(name, ContentSecurityPolicy::TreatAsPublicAddre ss)) { | 917 } else if (equalIgnoringCase(name, ContentSecurityPolicy::TreatAsPublicAddre ss)) { |
| 826 treatAsPublicAddress(name, value); | 918 treatAsPublicAddress(name, value); |
| 919 } else if (equalIgnoringCase(name, ContentSecurityPolicy::RequireSRIFor) && m_policy->experimentalFeaturesEnabled()) { | |
| 920 parseRequireSRIFor(name, value); | |
| 827 } else { | 921 } else { |
| 828 m_policy->reportUnsupportedDirective(name); | 922 m_policy->reportUnsupportedDirective(name); |
| 829 } | 923 } |
| 830 } | 924 } |
| 831 | 925 |
| 832 DEFINE_TRACE(CSPDirectiveList) | 926 DEFINE_TRACE(CSPDirectiveList) |
| 833 { | 927 { |
| 834 visitor->trace(m_policy); | 928 visitor->trace(m_policy); |
| 835 visitor->trace(m_pluginTypes); | 929 visitor->trace(m_pluginTypes); |
| 836 visitor->trace(m_baseURI); | 930 visitor->trace(m_baseURI); |
| 837 visitor->trace(m_childSrc); | 931 visitor->trace(m_childSrc); |
| 838 visitor->trace(m_connectSrc); | 932 visitor->trace(m_connectSrc); |
| 839 visitor->trace(m_defaultSrc); | 933 visitor->trace(m_defaultSrc); |
| 840 visitor->trace(m_fontSrc); | 934 visitor->trace(m_fontSrc); |
| 841 visitor->trace(m_formAction); | 935 visitor->trace(m_formAction); |
| 842 visitor->trace(m_frameAncestors); | 936 visitor->trace(m_frameAncestors); |
| 843 visitor->trace(m_frameSrc); | 937 visitor->trace(m_frameSrc); |
| 844 visitor->trace(m_imgSrc); | 938 visitor->trace(m_imgSrc); |
| 845 visitor->trace(m_mediaSrc); | 939 visitor->trace(m_mediaSrc); |
| 846 visitor->trace(m_manifestSrc); | 940 visitor->trace(m_manifestSrc); |
| 847 visitor->trace(m_objectSrc); | 941 visitor->trace(m_objectSrc); |
| 848 visitor->trace(m_scriptSrc); | 942 visitor->trace(m_scriptSrc); |
| 849 visitor->trace(m_styleSrc); | 943 visitor->trace(m_styleSrc); |
| 850 } | 944 } |
| 851 | 945 |
| 852 | 946 |
| 853 } // namespace blink | 947 } // namespace blink |
| OLD | NEW |