| Index: third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
|
| diff --git a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
|
| index d90f9266bb2925e3255599e4c592c0aeadb5c845..1dc66651c1812a54e4df936c33b84127bb99f7c0 100644
|
| --- a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
|
| +++ b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
|
| @@ -55,6 +55,7 @@ CSPDirectiveList::CSPDirectiveList(ContentSecurityPolicy* policy, ContentSecurit
|
| , m_strictMixedContentCheckingEnforced(false)
|
| , m_upgradeInsecureRequests(false)
|
| , m_treatAsPublicAddress(false)
|
| + , m_requireSRIFor(RequireSRIForToken::None)
|
| {
|
| m_reportOnly = type == ContentSecurityPolicyHeaderTypeReport;
|
| }
|
| @@ -173,6 +174,63 @@ bool CSPDirectiveList::checkAncestors(SourceListDirective* directive, LocalFrame
|
| return true;
|
| }
|
|
|
| +bool CSPDirectiveList::checkRequestWithoutIntegrity(WebURLRequest::RequestContext context) const
|
| +{
|
| + if (m_requireSRIFor == RequireSRIForToken::None)
|
| + return true;
|
| + // SRI specification (https://w3c.github.io/webappsec-subresource-integrity/#apply-algorithm-to-request)
|
| + // says to match token with request's destination with the token.
|
| + // Keep this logic aligned with ContentSecurityPolicy::allowRequest
|
| + if ((m_requireSRIFor & RequireSRIForToken::Script)
|
| + && (context == WebURLRequest::RequestContextScript
|
| + || context == WebURLRequest::RequestContextImport
|
| + || context == WebURLRequest::RequestContextServiceWorker
|
| + || context == WebURLRequest::RequestContextSharedWorker
|
| + || context == WebURLRequest::RequestContextWorker)) {
|
| + return false;
|
| + }
|
| + if ((m_requireSRIFor & RequireSRIForToken::Style) && context == WebURLRequest::RequestContextStyle)
|
| + return false;
|
| + return true;
|
| +}
|
| +
|
| +bool CSPDirectiveList::checkRequestWithoutIntegrityAndReportViolation(WebURLRequest::RequestContext context, const KURL& url, ResourceRequest::RedirectStatus redirectStatus) const
|
| +{
|
| + if (checkRequestWithoutIntegrity(context))
|
| + return true;
|
| + String resourceType;
|
| + switch (context) {
|
| + case WebURLRequest::RequestContextScript:
|
| + case WebURLRequest::RequestContextImport:
|
| + resourceType = "script";
|
| + break;
|
| + case WebURLRequest::RequestContextStyle:
|
| + resourceType = "stylesheet";
|
| + break;
|
| + case WebURLRequest::RequestContextServiceWorker:
|
| + resourceType = "service worker";
|
| + break;
|
| + case WebURLRequest::RequestContextSharedWorker:
|
| + resourceType = "shared worker";
|
| + break;
|
| + case WebURLRequest::RequestContextWorker:
|
| + resourceType = "worker";
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + reportViolation(ContentSecurityPolicy::RequireSRIFor, ContentSecurityPolicy::RequireSRIFor, "Refused to load the " + resourceType + " '" + url.elidedString() + "' because 'require-sri-for' directive requires integrity attribute be present for all " + resourceType + "s.", url, redirectStatus);
|
| + return denyIfEnforcingPolicy();
|
| +}
|
| +
|
| +bool CSPDirectiveList::allowRequestWithoutIntegrity(WebURLRequest::RequestContext context, const KURL& url, ResourceRequest::RedirectStatus redirectStatus, ContentSecurityPolicy::ReportingStatus reportingStatus) const
|
| +{
|
| + if (reportingStatus == ContentSecurityPolicy::SendReport)
|
| + return checkRequestWithoutIntegrityAndReportViolation(context, url, redirectStatus);
|
| + return denyIfEnforcingPolicy() || checkRequestWithoutIntegrity(context);
|
| +}
|
| +
|
| bool CSPDirectiveList::checkMediaType(MediaListDirective* directive, const String& type, const String& typeAttribute) const
|
| {
|
| if (!directive)
|
| @@ -551,6 +609,60 @@ bool CSPDirectiveList::parseDirective(const UChar* begin, const UChar* end, Stri
|
| return true;
|
| }
|
|
|
| +void CSPDirectiveList::parseRequireSRIFor(const String& name, const String& value)
|
| +{
|
| + if (m_requireSRIFor != 0) {
|
| + m_policy->reportDuplicateDirective(name);
|
| + return;
|
| + }
|
| + StringBuilder tokenErrors;
|
| + unsigned numberOfTokenErrors = 0;
|
| + Vector<UChar> characters;
|
| + value.appendTo(characters);
|
| +
|
| + const UChar* position = characters.data();
|
| + const UChar* end = position + characters.size();
|
| +
|
| + while (position < end) {
|
| + skipWhile<UChar, isASCIISpace>(position, end);
|
| +
|
| + const UChar* tokenBegin = position;
|
| + skipWhile<UChar, isNotASCIISpace>(position, end);
|
| +
|
| + if (tokenBegin < position) {
|
| + String token = String(tokenBegin, position - tokenBegin);
|
| + if (equalIgnoringCase(token, "script")) {
|
| + m_requireSRIFor |= RequireSRIForToken::Script;
|
| + } else if (equalIgnoringCase(token, "style")) {
|
| + m_requireSRIFor |= RequireSRIForToken::Style;
|
| + } else {
|
| + if (numberOfTokenErrors)
|
| + tokenErrors.append(", \'");
|
| + else
|
| + tokenErrors.append('\'');
|
| + tokenErrors.append(token);
|
| + tokenErrors.append('\'');
|
| + numberOfTokenErrors++;
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (numberOfTokenErrors == 0)
|
| + return;
|
| +
|
| + String invalidTokensErrorMessage;
|
| + if (numberOfTokenErrors > 1)
|
| + tokenErrors.append(" are invalid 'require-sri-for' tokens.");
|
| + else
|
| + tokenErrors.append(" is an invalid 'require-sri-for' token.");
|
| +
|
| + invalidTokensErrorMessage = tokenErrors.toString();
|
| +
|
| + DCHECK(!invalidTokensErrorMessage.isEmpty());
|
| +
|
| + m_policy->reportInvalidRequireSRIForTokens(invalidTokensErrorMessage);
|
| +}
|
| +
|
| void CSPDirectiveList::parseReportURI(const String& name, const String& value)
|
| {
|
| if (!m_reportEndpoints.isEmpty()) {
|
| @@ -824,6 +936,8 @@ void CSPDirectiveList::addDirective(const String& name, const String& value)
|
| setCSPDirective<SourceListDirective>(name, value, m_manifestSrc);
|
| } else if (equalIgnoringCase(name, ContentSecurityPolicy::TreatAsPublicAddress)) {
|
| treatAsPublicAddress(name, value);
|
| + } else if (equalIgnoringCase(name, ContentSecurityPolicy::RequireSRIFor) && m_policy->experimentalFeaturesEnabled()) {
|
| + parseRequireSRIFor(name, value);
|
| } else {
|
| m_policy->reportUnsupportedDirective(name);
|
| }
|
|
|