Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(497)

Unified Diff: third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp

Issue 2056183002: Implement the `require-sri-for` CSP directive (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Updated tests Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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);
}

Powered by Google App Engine
This is Rietveld 408576698