Chromium Code Reviews| 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..6532029981e205b6771ec2c20d206c4ea95a1355 100644 |
| --- a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp |
| +++ b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp |
| @@ -173,6 +173,51 @@ bool CSPDirectiveList::checkAncestors(SourceListDirective* directive, LocalFrame |
| return true; |
| } |
| +bool CSPDirectiveList::checkIntegrityPresence(WebURLRequest::RequestContext context, const IntegrityMetadataSet& integrityMetadata) const |
| +{ |
| + if (!integrityMetadata.isEmpty()) |
| + return true; |
| + |
| + if (m_requireSRIFor.isEmpty()) |
| + return true; |
| + |
| + for (const auto& token : m_requireSRIFor) { |
| + if (equalIgnoringCase(token, "script")) { |
| + if (context == WebURLRequest::RequestContextScript || context == WebURLRequest::RequestContextImport) { |
| + if (integrityMetadata.isEmpty()) |
| + return false; |
| + } |
| + } else if (equalIgnoringCase(token, "style")) { |
| + if (context == WebURLRequest::RequestContextStyle) { |
| + if (integrityMetadata.isEmpty()) |
| + return false; |
| + } |
| + } |
| + } |
| + return true; |
| +} |
| + |
| +bool CSPDirectiveList::checkIntegrityPresenceAndReportViolation(WebURLRequest::RequestContext context, const KURL& url, const IntegrityMetadataSet& integrityMetadata) const |
| +{ |
| + if (checkIntegrityPresence(context, integrityMetadata)) |
| + return true; |
| + String resourceType; |
| + if (context == WebURLRequest::RequestContextScript || context == WebURLRequest::RequestContextImport) |
|
jww
2016/06/11 22:45:12
Treating RequestContextImport as guaranteed to be
Sergey Shekyan
2016/06/20 07:12:00
I inherited the logic that RequestContextImport is
Mike West
2016/06/20 08:11:37
Right. Contexts are from an earlier version of Fet
|
| + resourceType = "script"; |
| + else if (context == WebURLRequest::RequestContextStyle) |
| + resourceType = "stylesheet"; |
| + 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, ResourceRequest::RedirectStatus::NoRedirect); |
|
Mike West
2016/06/10 09:25:15
`NoRedirect` probably isn't correct here, as I thi
Sergey Shekyan
2016/06/20 07:11:59
Acknowledged.
|
| + return denyIfEnforcingPolicy(); |
| +} |
| + |
| +bool CSPDirectiveList::allowRequestWithoutMetadata(WebURLRequest::RequestContext context, const KURL& url, const IntegrityMetadataSet& integrityMetadata, ContentSecurityPolicy::ReportingStatus reportingStatus) const |
| +{ |
| + if (reportingStatus == ContentSecurityPolicy::SendReport) { |
| + return checkIntegrityPresenceAndReportViolation(context, url, integrityMetadata); |
| + } |
| + return checkIntegrityPresence(context, integrityMetadata); |
| +} |
| + |
| bool CSPDirectiveList::checkMediaType(MediaListDirective* directive, const String& type, const String& typeAttribute) const |
| { |
| if (!directive) |
| @@ -551,6 +596,62 @@ bool CSPDirectiveList::parseDirective(const UChar* begin, const UChar* end, Stri |
| return true; |
| } |
| +void CSPDirectiveList::parseRequireSRIFor(const String& name, const String& value) |
| +{ |
| + if (!m_requireSRIFor.isEmpty()) { |
| + m_policy->reportDuplicateDirective(name); |
| + return; |
| + } |
| + StringBuilder tokenErrors; |
| + StringBuilder validTokens; |
| + 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") || equalIgnoringCase(token, "style")) { |
| + m_requireSRIFor.append(token); |
| + if (!validTokens.isEmpty()) |
| + validTokens.append(' '); |
| + validTokens.append(token); |
| + } 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(); |
| + |
| + if (!invalidTokensErrorMessage.isEmpty()) { |
|
jww
2016/06/11 22:45:12
I think inavildTokensErrorMessage cannot be empty
Sergey Shekyan
2016/06/20 07:12:00
Acknowledged.
|
| + m_policy->reportInvalidRequireSRIForTokens(invalidTokensErrorMessage); |
| + } |
| +} |
| + |
| void CSPDirectiveList::parseReportURI(const String& name, const String& value) |
| { |
| if (!m_reportEndpoints.isEmpty()) { |
| @@ -824,6 +925,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)) { |
| + parseRequireSRIFor(name, value); |
|
Mike West
2016/06/10 09:25:15
This functionality should be hidden behind the exp
Sergey Shekyan
2016/06/20 07:12:00
Acknowledged.
|
| } else { |
| m_policy->reportUnsupportedDirective(name); |
| } |