Commit e9932e62 authored by mkwst@chromium.org's avatar mkwst@chromium.org

CSP: Separate more parse-time side-effects.

This patch does two things:

* The single parse-time UseCounter is now out of the parsing flow, and
  in the side-effects method.

* Parse-time ConsoleMessages generated in ContentSecurityPolicy and
  CSPDirectiveList are now stored on ContentSecurityPolicy and spun out
  to the console in the side-effects method.

BUG=411889

Review URL: https://codereview.chromium.org/554303002

git-svn-id: svn://svn.chromium.org/blink/trunk@181715 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 24651064
...@@ -25,7 +25,7 @@ public: ...@@ -25,7 +25,7 @@ public:
const String& text() const { return m_text; } const String& text() const { return m_text; }
protected: protected:
const ContentSecurityPolicy* policy() const { return m_policy; } ContentSecurityPolicy* policy() const { return m_policy; }
private: private:
String m_name; String m_name;
......
...@@ -46,14 +46,14 @@ PassOwnPtr<CSPDirectiveList> CSPDirectiveList::create(ContentSecurityPolicy* pol ...@@ -46,14 +46,14 @@ PassOwnPtr<CSPDirectiveList> CSPDirectiveList::create(ContentSecurityPolicy* pol
void CSPDirectiveList::reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL) const void CSPDirectiveList::reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL) const
{ {
String message = m_reportOnly ? "[Report Only] " + consoleMessage : consoleMessage; String message = m_reportOnly ? "[Report Only] " + consoleMessage : consoleMessage;
m_policy->executionContext()->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, message)); m_policy->logToConsole(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, message));
m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportURIs, m_header); m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportURIs, m_header);
} }
void CSPDirectiveList::reportViolationWithLocation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const String& contextURL, const WTF::OrdinalNumber& contextLine) const void CSPDirectiveList::reportViolationWithLocation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const String& contextURL, const WTF::OrdinalNumber& contextLine) const
{ {
String message = m_reportOnly ? "[Report Only] " + consoleMessage : consoleMessage; String message = m_reportOnly ? "[Report Only] " + consoleMessage : consoleMessage;
m_policy->executionContext()->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, message, contextURL, contextLine.oneBasedInt())); m_policy->logToConsole(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, message, contextURL, contextLine.oneBasedInt()));
m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportURIs, m_header); m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportURIs, m_header);
} }
...@@ -62,7 +62,7 @@ void CSPDirectiveList::reportViolationWithState(const String& directiveText, con ...@@ -62,7 +62,7 @@ void CSPDirectiveList::reportViolationWithState(const String& directiveText, con
String reportMessage = m_reportOnly ? "[Report Only] " + message : message; String reportMessage = m_reportOnly ? "[Report Only] " + message : message;
RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, reportMessage); RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, reportMessage);
consoleMessage->setScriptState(scriptState); consoleMessage->setScriptState(scriptState);
m_policy->executionContext()->addConsoleMessage(consoleMessage.release()); m_policy->logToConsole(consoleMessage.release());
m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportURIs, m_header); m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportURIs, m_header);
} }
......
...@@ -146,11 +146,19 @@ void ContentSecurityPolicy::applyPolicySideEffectsToExecutionContext() ...@@ -146,11 +146,19 @@ void ContentSecurityPolicy::applyPolicySideEffectsToExecutionContext()
// Ensure that 'self' processes correctly. // Ensure that 'self' processes correctly.
m_selfSource = adoptPtr(new CSPSource(this, securityOrigin()->protocol(), securityOrigin()->host(), securityOrigin()->port(), String(), false, false)); m_selfSource = adoptPtr(new CSPSource(this, securityOrigin()->protocol(), securityOrigin()->host(), securityOrigin()->port(), String(), false, false));
// If we're in a Document, set the referrer policy and sandbox flags. // If we're in a Document, set the referrer policy and sandbox flags, then dump all the
// parsing error messages, then poke at histograms.
if (Document* document = this->document()) { if (Document* document = this->document()) {
document->enforceSandboxFlags(m_sandboxMask); document->enforceSandboxFlags(m_sandboxMask);
if (didSetReferrerPolicy()) if (didSetReferrerPolicy())
document->setReferrerPolicy(m_referrerPolicy); document->setReferrerPolicy(m_referrerPolicy);
for (ConsoleMessageVector::const_iterator iter = m_consoleMessages.begin(); iter != m_consoleMessages.end(); ++iter)
executionContext()->addConsoleMessage(*iter);
m_consoleMessages.clear();
for (CSPDirectiveListVector::const_iterator iter = m_policies.begin(); iter != m_policies.end(); ++iter)
UseCounter::count(*document, getUseCounterType((*iter)->headerType()));
} }
// We disable 'eval()' even in the case of report-only policies, and rely on the check in the // We disable 'eval()' even in the case of report-only policies, and rely on the check in the
...@@ -201,18 +209,9 @@ void ContentSecurityPolicy::didReceiveHeader(const String& header, ContentSecuri ...@@ -201,18 +209,9 @@ void ContentSecurityPolicy::didReceiveHeader(const String& header, ContentSecuri
void ContentSecurityPolicy::addPolicyFromHeaderValue(const String& header, ContentSecurityPolicyHeaderType type, ContentSecurityPolicyHeaderSource source) void ContentSecurityPolicy::addPolicyFromHeaderValue(const String& header, ContentSecurityPolicyHeaderType type, ContentSecurityPolicyHeaderSource source)
{ {
Document* document = this->document(); if (source == ContentSecurityPolicyHeaderSourceMeta && type == ContentSecurityPolicyHeaderTypeReport && experimentalFeaturesEnabled()) {
if (document) { reportReportOnlyInMeta(header);
UseCounter::count(*document, getUseCounterType(type)); return;
// CSP 1.1 defines report-only in a <meta> element as invalid. Measure for now, disable in experimental mode.
if (source == ContentSecurityPolicyHeaderSourceMeta && type == ContentSecurityPolicyHeaderTypeReport) {
UseCounter::count(*document, UseCounter::ContentSecurityPolicyReportOnlyInMeta);
if (experimentalFeaturesEnabled()) {
reportReportOnlyInMeta(header);
return;
}
}
} }
Vector<UChar> characters; Vector<UChar> characters;
...@@ -680,27 +679,27 @@ void ContentSecurityPolicy::reportViolation(const String& directiveText, const S ...@@ -680,27 +679,27 @@ void ContentSecurityPolicy::reportViolation(const String& directiveText, const S
didSendViolationReport(stringifiedReport); didSendViolationReport(stringifiedReport);
} }
void ContentSecurityPolicy::reportInvalidReferrer(const String& invalidValue) const void ContentSecurityPolicy::reportInvalidReferrer(const String& invalidValue)
{ {
logToConsole("The 'referrer' Content Security Policy directive has the invalid value \"" + invalidValue + "\". Valid values are \"always\", \"default\", \"never\", and \"origin\"."); logToConsole("The 'referrer' Content Security Policy directive has the invalid value \"" + invalidValue + "\". Valid values are \"always\", \"default\", \"never\", and \"origin\".");
} }
void ContentSecurityPolicy::reportReportOnlyInMeta(const String& header) const void ContentSecurityPolicy::reportReportOnlyInMeta(const String& header)
{ {
logToConsole("The report-only Content Security Policy '" + header + "' was delivered via a <meta> element, which is disallowed. The policy has been ignored."); logToConsole("The report-only Content Security Policy '" + header + "' was delivered via a <meta> element, which is disallowed. The policy has been ignored.");
} }
void ContentSecurityPolicy::reportMetaOutsideHead(const String& header) const void ContentSecurityPolicy::reportMetaOutsideHead(const String& header)
{ {
logToConsole("The Content Security Policy '" + header + "' was delivered via a <meta> element outside the document's <head>, which is disallowed. The policy has been ignored."); logToConsole("The Content Security Policy '" + header + "' was delivered via a <meta> element outside the document's <head>, which is disallowed. The policy has been ignored.");
} }
void ContentSecurityPolicy::reportInvalidInReportOnly(const String& name) const void ContentSecurityPolicy::reportInvalidInReportOnly(const String& name)
{ {
logToConsole("The Content Security Policy directive '" + name + "' is ignored when delivered in a report-only policy."); logToConsole("The Content Security Policy directive '" + name + "' is ignored when delivered in a report-only policy.");
} }
void ContentSecurityPolicy::reportUnsupportedDirective(const String& name) const void ContentSecurityPolicy::reportUnsupportedDirective(const String& name)
{ {
DEFINE_STATIC_LOCAL(String, allow, ("allow")); DEFINE_STATIC_LOCAL(String, allow, ("allow"));
DEFINE_STATIC_LOCAL(String, options, ("options")); DEFINE_STATIC_LOCAL(String, options, ("options"));
...@@ -725,19 +724,19 @@ void ContentSecurityPolicy::reportUnsupportedDirective(const String& name) const ...@@ -725,19 +724,19 @@ void ContentSecurityPolicy::reportUnsupportedDirective(const String& name) const
logToConsole(message, level); logToConsole(message, level);
} }
void ContentSecurityPolicy::reportDirectiveAsSourceExpression(const String& directiveName, const String& sourceExpression) const void ContentSecurityPolicy::reportDirectiveAsSourceExpression(const String& directiveName, const String& sourceExpression)
{ {
String message = "The Content Security Policy directive '" + directiveName + "' contains '" + sourceExpression + "' as a source expression. Did you mean '" + directiveName + " ...; " + sourceExpression + "...' (note the semicolon)?"; String message = "The Content Security Policy directive '" + directiveName + "' contains '" + sourceExpression + "' as a source expression. Did you mean '" + directiveName + " ...; " + sourceExpression + "...' (note the semicolon)?";
logToConsole(message); logToConsole(message);
} }
void ContentSecurityPolicy::reportDuplicateDirective(const String& name) const void ContentSecurityPolicy::reportDuplicateDirective(const String& name)
{ {
String message = "Ignoring duplicate Content-Security-Policy directive '" + name + "'.\n"; String message = "Ignoring duplicate Content-Security-Policy directive '" + name + "'.\n";
logToConsole(message); logToConsole(message);
} }
void ContentSecurityPolicy::reportInvalidPluginTypes(const String& pluginType) const void ContentSecurityPolicy::reportInvalidPluginTypes(const String& pluginType)
{ {
String message; String message;
if (pluginType.isNull()) if (pluginType.isNull())
...@@ -747,23 +746,23 @@ void ContentSecurityPolicy::reportInvalidPluginTypes(const String& pluginType) c ...@@ -747,23 +746,23 @@ void ContentSecurityPolicy::reportInvalidPluginTypes(const String& pluginType) c
logToConsole(message); logToConsole(message);
} }
void ContentSecurityPolicy::reportInvalidSandboxFlags(const String& invalidFlags) const void ContentSecurityPolicy::reportInvalidSandboxFlags(const String& invalidFlags)
{ {
logToConsole("Error while parsing the 'sandbox' Content Security Policy directive: " + invalidFlags); logToConsole("Error while parsing the 'sandbox' Content Security Policy directive: " + invalidFlags);
} }
void ContentSecurityPolicy::reportInvalidReflectedXSS(const String& invalidValue) const void ContentSecurityPolicy::reportInvalidReflectedXSS(const String& invalidValue)
{ {
logToConsole("The 'reflected-xss' Content Security Policy directive has the invalid value \"" + invalidValue + "\". Valid values are \"allow\", \"filter\", and \"block\"."); logToConsole("The 'reflected-xss' Content Security Policy directive has the invalid value \"" + invalidValue + "\". Valid values are \"allow\", \"filter\", and \"block\".");
} }
void ContentSecurityPolicy::reportInvalidDirectiveValueCharacter(const String& directiveName, const String& value) const void ContentSecurityPolicy::reportInvalidDirectiveValueCharacter(const String& directiveName, const String& value)
{ {
String message = "The value for Content Security Policy directive '" + directiveName + "' contains an invalid character: '" + value + "'. Non-whitespace characters outside ASCII 0x21-0x7E must be percent-encoded, as described in RFC 3986, section 2.1: http://tools.ietf.org/html/rfc3986#section-2.1."; String message = "The value for Content Security Policy directive '" + directiveName + "' contains an invalid character: '" + value + "'. Non-whitespace characters outside ASCII 0x21-0x7E must be percent-encoded, as described in RFC 3986, section 2.1: http://tools.ietf.org/html/rfc3986#section-2.1.";
logToConsole(message); logToConsole(message);
} }
void ContentSecurityPolicy::reportInvalidPathCharacter(const String& directiveName, const String& value, const char invalidChar) const void ContentSecurityPolicy::reportInvalidPathCharacter(const String& directiveName, const String& value, const char invalidChar)
{ {
ASSERT(invalidChar == '#' || invalidChar == '?'); ASSERT(invalidChar == '#' || invalidChar == '?');
...@@ -774,7 +773,7 @@ void ContentSecurityPolicy::reportInvalidPathCharacter(const String& directiveNa ...@@ -774,7 +773,7 @@ void ContentSecurityPolicy::reportInvalidPathCharacter(const String& directiveNa
logToConsole(message); logToConsole(message);
} }
void ContentSecurityPolicy::reportInvalidSourceExpression(const String& directiveName, const String& source) const void ContentSecurityPolicy::reportInvalidSourceExpression(const String& directiveName, const String& source)
{ {
String message = "The source list for Content Security Policy directive '" + directiveName + "' contains an invalid source: '" + source + "'. It will be ignored."; String message = "The source list for Content Security Policy directive '" + directiveName + "' contains an invalid source: '" + source + "'. It will be ignored.";
if (equalIgnoringCase(source, "'none'")) if (equalIgnoringCase(source, "'none'"))
...@@ -782,14 +781,22 @@ void ContentSecurityPolicy::reportInvalidSourceExpression(const String& directiv ...@@ -782,14 +781,22 @@ void ContentSecurityPolicy::reportInvalidSourceExpression(const String& directiv
logToConsole(message); logToConsole(message);
} }
void ContentSecurityPolicy::reportMissingReportURI(const String& policy) const void ContentSecurityPolicy::reportMissingReportURI(const String& policy)
{ {
logToConsole("The Content Security Policy '" + policy + "' was delivered in report-only mode, but does not specify a 'report-uri'; the policy will have no effect. Please either add a 'report-uri' directive, or deliver the policy via the 'Content-Security-Policy' header."); logToConsole("The Content Security Policy '" + policy + "' was delivered in report-only mode, but does not specify a 'report-uri'; the policy will have no effect. Please either add a 'report-uri' directive, or deliver the policy via the 'Content-Security-Policy' header.");
} }
void ContentSecurityPolicy::logToConsole(const String& message, MessageLevel level) const void ContentSecurityPolicy::logToConsole(const String& message, MessageLevel level)
{ {
m_executionContext->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, level, message)); logToConsole(ConsoleMessage::create(SecurityMessageSource, level, message));
}
void ContentSecurityPolicy::logToConsole(PassRefPtr<ConsoleMessage> consoleMessage)
{
if (m_executionContext)
m_executionContext->addConsoleMessage(consoleMessage);
else
m_consoleMessages.append(consoleMessage);
} }
void ContentSecurityPolicy::reportBlockedScriptExecutionToInspector(const String& directiveText) const void ContentSecurityPolicy::reportBlockedScriptExecutionToInspector(const String& directiveText) const
......
...@@ -48,6 +48,7 @@ class OrdinalNumber; ...@@ -48,6 +48,7 @@ class OrdinalNumber;
namespace blink { namespace blink {
class ContentSecurityPolicyResponseHeaders; class ContentSecurityPolicyResponseHeaders;
class ConsoleMessage;
class CSPDirectiveList; class CSPDirectiveList;
class CSPSource; class CSPSource;
class DOMStringList; class DOMStringList;
...@@ -58,6 +59,7 @@ class SecurityOrigin; ...@@ -58,6 +59,7 @@ class SecurityOrigin;
typedef int SandboxFlags; typedef int SandboxFlags;
typedef Vector<OwnPtr<CSPDirectiveList> > CSPDirectiveListVector; typedef Vector<OwnPtr<CSPDirectiveList> > CSPDirectiveListVector;
typedef Vector<RefPtrWillBeRawPtr<ConsoleMessage> > ConsoleMessageVector;
class ContentSecurityPolicy : public RefCounted<ContentSecurityPolicy> { class ContentSecurityPolicy : public RefCounted<ContentSecurityPolicy> {
WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_FAST_ALLOCATED;
...@@ -154,20 +156,22 @@ public: ...@@ -154,20 +156,22 @@ public:
bool isActive() const; bool isActive() const;
void reportDirectiveAsSourceExpression(const String& directiveName, const String& sourceExpression) const; void logToConsole(PassRefPtr<ConsoleMessage>);
void reportDuplicateDirective(const String&) const;
void reportInvalidDirectiveValueCharacter(const String& directiveName, const String& value) const; void reportDirectiveAsSourceExpression(const String& directiveName, const String& sourceExpression);
void reportInvalidPathCharacter(const String& directiveName, const String& value, const char) const; void reportDuplicateDirective(const String&);
void reportInvalidPluginTypes(const String&) const; void reportInvalidDirectiveValueCharacter(const String& directiveName, const String& value);
void reportInvalidSandboxFlags(const String&) const; void reportInvalidPathCharacter(const String& directiveName, const String& value, const char);
void reportInvalidSourceExpression(const String& directiveName, const String& source) const; void reportInvalidPluginTypes(const String&);
void reportInvalidReflectedXSS(const String&) const; void reportInvalidSandboxFlags(const String&);
void reportMissingReportURI(const String&) const; void reportInvalidSourceExpression(const String& directiveName, const String& source);
void reportUnsupportedDirective(const String&) const; void reportInvalidReflectedXSS(const String&);
void reportInvalidInReportOnly(const String&) const; void reportMissingReportURI(const String&);
void reportInvalidReferrer(const String&) const; void reportUnsupportedDirective(const String&);
void reportReportOnlyInMeta(const String&) const; void reportInvalidInReportOnly(const String&);
void reportMetaOutsideHead(const String&) const; void reportInvalidReferrer(const String&);
void reportReportOnlyInMeta(const String&);
void reportMetaOutsideHead(const String&);
void reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const Vector<KURL>& reportURIs, const String& header); void reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const Vector<KURL>& reportURIs, const String& header);
void reportBlockedScriptExecutionToInspector(const String& directiveText) const; void reportBlockedScriptExecutionToInspector(const String& directiveText) const;
...@@ -196,7 +200,7 @@ private: ...@@ -196,7 +200,7 @@ private:
Document* document() const; Document* document() const;
SecurityOrigin* securityOrigin() const; SecurityOrigin* securityOrigin() const;
void logToConsole(const String& message, MessageLevel = ErrorMessageLevel) const; void logToConsole(const String& message, MessageLevel = ErrorMessageLevel);
void addPolicyFromHeaderValue(const String&, ContentSecurityPolicyHeaderType, ContentSecurityPolicyHeaderSource); void addPolicyFromHeaderValue(const String&, ContentSecurityPolicyHeaderType, ContentSecurityPolicyHeaderSource);
bool shouldSendViolationReport(const String&) const; bool shouldSendViolationReport(const String&) const;
...@@ -205,6 +209,7 @@ private: ...@@ -205,6 +209,7 @@ private:
ExecutionContext* m_executionContext; ExecutionContext* m_executionContext;
bool m_overrideInlineStyleAllowed; bool m_overrideInlineStyleAllowed;
CSPDirectiveListVector m_policies; CSPDirectiveListVector m_policies;
ConsoleMessageVector m_consoleMessages;
HashSet<unsigned, AlreadyHashed> m_violationReportsSent; HashSet<unsigned, AlreadyHashed> m_violationReportsSent;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment