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:
const String& text() const { return m_text; }
protected:
const ContentSecurityPolicy* policy() const { return m_policy; }
ContentSecurityPolicy* policy() const { return m_policy; }
private:
String m_name;
......
......@@ -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
{
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);
}
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;
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);
}
......@@ -62,7 +62,7 @@ void CSPDirectiveList::reportViolationWithState(const String& directiveText, con
String reportMessage = m_reportOnly ? "[Report Only] " + message : message;
RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, reportMessage);
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);
}
......
......@@ -146,11 +146,19 @@ void ContentSecurityPolicy::applyPolicySideEffectsToExecutionContext()
// Ensure that 'self' processes correctly.
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()) {
document->enforceSandboxFlags(m_sandboxMask);
if (didSetReferrerPolicy())
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
......@@ -201,19 +209,10 @@ void ContentSecurityPolicy::didReceiveHeader(const String& header, ContentSecuri
void ContentSecurityPolicy::addPolicyFromHeaderValue(const String& header, ContentSecurityPolicyHeaderType type, ContentSecurityPolicyHeaderSource source)
{
Document* document = this->document();
if (document) {
UseCounter::count(*document, getUseCounterType(type));
// 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()) {
if (source == ContentSecurityPolicyHeaderSourceMeta && type == ContentSecurityPolicyHeaderTypeReport && experimentalFeaturesEnabled()) {
reportReportOnlyInMeta(header);
return;
}
}
}
Vector<UChar> characters;
header.appendTo(characters);
......@@ -680,27 +679,27 @@ void ContentSecurityPolicy::reportViolation(const String& directiveText, const S
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\".");
}
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.");
}
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.");
}
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.");
}
void ContentSecurityPolicy::reportUnsupportedDirective(const String& name) const
void ContentSecurityPolicy::reportUnsupportedDirective(const String& name)
{
DEFINE_STATIC_LOCAL(String, allow, ("allow"));
DEFINE_STATIC_LOCAL(String, options, ("options"));
......@@ -725,19 +724,19 @@ void ContentSecurityPolicy::reportUnsupportedDirective(const String& name) const
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)?";
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";
logToConsole(message);
}
void ContentSecurityPolicy::reportInvalidPluginTypes(const String& pluginType) const
void ContentSecurityPolicy::reportInvalidPluginTypes(const String& pluginType)
{
String message;
if (pluginType.isNull())
......@@ -747,23 +746,23 @@ void ContentSecurityPolicy::reportInvalidPluginTypes(const String& pluginType) c
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);
}
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\".");
}
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.";
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 == '?');
......@@ -774,7 +773,7 @@ void ContentSecurityPolicy::reportInvalidPathCharacter(const String& directiveNa
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.";
if (equalIgnoringCase(source, "'none'"))
......@@ -782,14 +781,22 @@ void ContentSecurityPolicy::reportInvalidSourceExpression(const String& directiv
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.");
}
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
......
......@@ -48,6 +48,7 @@ class OrdinalNumber;
namespace blink {
class ContentSecurityPolicyResponseHeaders;
class ConsoleMessage;
class CSPDirectiveList;
class CSPSource;
class DOMStringList;
......@@ -58,6 +59,7 @@ class SecurityOrigin;
typedef int SandboxFlags;
typedef Vector<OwnPtr<CSPDirectiveList> > CSPDirectiveListVector;
typedef Vector<RefPtrWillBeRawPtr<ConsoleMessage> > ConsoleMessageVector;
class ContentSecurityPolicy : public RefCounted<ContentSecurityPolicy> {
WTF_MAKE_FAST_ALLOCATED;
......@@ -154,20 +156,22 @@ public:
bool isActive() const;
void reportDirectiveAsSourceExpression(const String& directiveName, const String& sourceExpression) const;
void reportDuplicateDirective(const String&) const;
void reportInvalidDirectiveValueCharacter(const String& directiveName, const String& value) const;
void reportInvalidPathCharacter(const String& directiveName, const String& value, const char) const;
void reportInvalidPluginTypes(const String&) const;
void reportInvalidSandboxFlags(const String&) const;
void reportInvalidSourceExpression(const String& directiveName, const String& source) const;
void reportInvalidReflectedXSS(const String&) const;
void reportMissingReportURI(const String&) const;
void reportUnsupportedDirective(const String&) const;
void reportInvalidInReportOnly(const String&) const;
void reportInvalidReferrer(const String&) const;
void reportReportOnlyInMeta(const String&) const;
void reportMetaOutsideHead(const String&) const;
void logToConsole(PassRefPtr<ConsoleMessage>);
void reportDirectiveAsSourceExpression(const String& directiveName, const String& sourceExpression);
void reportDuplicateDirective(const String&);
void reportInvalidDirectiveValueCharacter(const String& directiveName, const String& value);
void reportInvalidPathCharacter(const String& directiveName, const String& value, const char);
void reportInvalidPluginTypes(const String&);
void reportInvalidSandboxFlags(const String&);
void reportInvalidSourceExpression(const String& directiveName, const String& source);
void reportInvalidReflectedXSS(const String&);
void reportMissingReportURI(const String&);
void reportUnsupportedDirective(const String&);
void reportInvalidInReportOnly(const String&);
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 reportBlockedScriptExecutionToInspector(const String& directiveText) const;
......@@ -196,7 +200,7 @@ private:
Document* document() 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);
bool shouldSendViolationReport(const String&) const;
......@@ -205,6 +209,7 @@ private:
ExecutionContext* m_executionContext;
bool m_overrideInlineStyleAllowed;
CSPDirectiveListVector m_policies;
ConsoleMessageVector m_consoleMessages;
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