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

Extract CSPDirectiveList from ContentSecurityPolicy.

BUG=346642

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

git-svn-id: svn://svn.chromium.org/blink/trunk@168451 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent c1e044f7
...@@ -1093,6 +1093,7 @@ ...@@ -1093,6 +1093,7 @@
'frame/SuspendableTimer.cpp', 'frame/SuspendableTimer.cpp',
'frame/SuspendableTimer.h', 'frame/SuspendableTimer.h',
'frame/UseCounter.cpp', 'frame/UseCounter.cpp',
'frame/csp/CSPDirectiveList.cpp',
'frame/csp/CSPSource.cpp', 'frame/csp/CSPSource.cpp',
'frame/csp/CSPSourceList.cpp', 'frame/csp/CSPSourceList.cpp',
'frame/csp/MediaListDirective.cpp', 'frame/csp/MediaListDirective.cpp',
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "core/frame/DOMWindow.h" #include "core/frame/DOMWindow.h"
#include "core/frame/LocalFrame.h" #include "core/frame/LocalFrame.h"
#include "core/frame/UseCounter.h" #include "core/frame/UseCounter.h"
#include "core/frame/csp/CSPDirectiveList.h"
#include "core/frame/csp/CSPSource.h" #include "core/frame/csp/CSPSource.h"
#include "core/frame/csp/CSPSourceList.h" #include "core/frame/csp/CSPSourceList.h"
#include "core/frame/csp/MediaListDirective.h" #include "core/frame/csp/MediaListDirective.h"
...@@ -65,47 +66,47 @@ ...@@ -65,47 +66,47 @@
namespace WebCore { namespace WebCore {
// CSP 1.0 Directives // CSP 1.0 Directives
static const char connectSrc[] = "connect-src"; const char ContentSecurityPolicy::ConnectSrc[] = "connect-src";
static const char defaultSrc[] = "default-src"; const char ContentSecurityPolicy::DefaultSrc[] = "default-src";
static const char fontSrc[] = "font-src"; const char ContentSecurityPolicy::FontSrc[] = "font-src";
static const char frameSrc[] = "frame-src"; const char ContentSecurityPolicy::FrameSrc[] = "frame-src";
static const char imgSrc[] = "img-src"; const char ContentSecurityPolicy::ImgSrc[] = "img-src";
static const char mediaSrc[] = "media-src"; const char ContentSecurityPolicy::MediaSrc[] = "media-src";
static const char objectSrc[] = "object-src"; const char ContentSecurityPolicy::ObjectSrc[] = "object-src";
static const char reportURI[] = "report-uri"; const char ContentSecurityPolicy::ReportURI[] = "report-uri";
static const char sandbox[] = "sandbox"; const char ContentSecurityPolicy::Sandbox[] = "sandbox";
static const char scriptSrc[] = "script-src"; const char ContentSecurityPolicy::ScriptSrc[] = "script-src";
static const char styleSrc[] = "style-src"; const char ContentSecurityPolicy::StyleSrc[] = "style-src";
// CSP 1.1 Directives // CSP 1.1 Directives
static const char baseURI[] = "base-uri"; const char ContentSecurityPolicy::BaseURI[] = "base-uri";
static const char childSrc[] = "child-src"; const char ContentSecurityPolicy::ChildSrc[] = "child-src";
static const char formAction[] = "form-action"; const char ContentSecurityPolicy::FormAction[] = "form-action";
static const char frameAncestors[] = "frame-ancestors"; const char ContentSecurityPolicy::FrameAncestors[] = "frame-ancestors";
static const char pluginTypes[] = "plugin-types"; const char ContentSecurityPolicy::PluginTypes[] = "plugin-types";
static const char reflectedXSS[] = "reflected-xss"; const char ContentSecurityPolicy::ReflectedXSS[] = "reflected-xss";
static const char referrer[] = "referrer"; const char ContentSecurityPolicy::Referrer[] = "referrer";
bool ContentSecurityPolicy::isDirectiveName(const String& name) bool ContentSecurityPolicy::isDirectiveName(const String& name)
{ {
return (equalIgnoringCase(name, connectSrc) return (equalIgnoringCase(name, ConnectSrc)
|| equalIgnoringCase(name, defaultSrc) || equalIgnoringCase(name, DefaultSrc)
|| equalIgnoringCase(name, fontSrc) || equalIgnoringCase(name, FontSrc)
|| equalIgnoringCase(name, frameSrc) || equalIgnoringCase(name, FrameSrc)
|| equalIgnoringCase(name, imgSrc) || equalIgnoringCase(name, ImgSrc)
|| equalIgnoringCase(name, mediaSrc) || equalIgnoringCase(name, MediaSrc)
|| equalIgnoringCase(name, objectSrc) || equalIgnoringCase(name, ObjectSrc)
|| equalIgnoringCase(name, reportURI) || equalIgnoringCase(name, ReportURI)
|| equalIgnoringCase(name, sandbox) || equalIgnoringCase(name, Sandbox)
|| equalIgnoringCase(name, scriptSrc) || equalIgnoringCase(name, ScriptSrc)
|| equalIgnoringCase(name, styleSrc) || equalIgnoringCase(name, StyleSrc)
|| equalIgnoringCase(name, baseURI) || equalIgnoringCase(name, BaseURI)
|| equalIgnoringCase(name, childSrc) || equalIgnoringCase(name, ChildSrc)
|| equalIgnoringCase(name, formAction) || equalIgnoringCase(name, FormAction)
|| equalIgnoringCase(name, frameAncestors) || equalIgnoringCase(name, FrameAncestors)
|| equalIgnoringCase(name, pluginTypes) || equalIgnoringCase(name, PluginTypes)
|| equalIgnoringCase(name, reflectedXSS) || equalIgnoringCase(name, ReflectedXSS)
|| equalIgnoringCase(name, referrer) || equalIgnoringCase(name, Referrer)
); );
} }
...@@ -128,782 +129,6 @@ static ReferrerPolicy mergeReferrerPolicies(ReferrerPolicy a, ReferrerPolicy b) ...@@ -128,782 +129,6 @@ static ReferrerPolicy mergeReferrerPolicies(ReferrerPolicy a, ReferrerPolicy b)
return a; return a;
} }
class CSPDirectiveList {
WTF_MAKE_FAST_ALLOCATED;
public:
static PassOwnPtr<CSPDirectiveList> create(ContentSecurityPolicy*, const UChar* begin, const UChar* end, ContentSecurityPolicyHeaderType, ContentSecurityPolicyHeaderSource);
void parse(const UChar* begin, const UChar* end);
const String& header() const { return m_header; }
ContentSecurityPolicyHeaderType headerType() const { return m_headerType; }
ContentSecurityPolicyHeaderSource headerSource() const { return m_headerSource; }
bool allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
bool allowInlineEventHandlers(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
bool allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
bool allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
bool allowEval(ScriptState*, ContentSecurityPolicy::ReportingStatus) const;
bool allowPluginType(const String& type, const String& typeAttribute, const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowScriptFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowObjectFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowChildFrameFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowImageFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowStyleFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowFontFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowMediaFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowConnectToSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowFormAction(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowBaseURI(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowAncestors(LocalFrame*, ContentSecurityPolicy::ReportingStatus) const;
bool allowChildContextFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowScriptNonce(const String&) const;
bool allowStyleNonce(const String&) const;
bool allowScriptHash(const CSPHashValue&) const;
bool allowStyleHash(const CSPHashValue&) const;
const String& evalDisabledErrorMessage() const { return m_evalDisabledErrorMessage; }
ReflectedXSSDisposition reflectedXSSDisposition() const { return m_reflectedXSSDisposition; }
ReferrerPolicy referrerPolicy() const { return m_referrerPolicy; }
bool didSetReferrerPolicy() const { return m_didSetReferrerPolicy; }
bool isReportOnly() const { return m_reportOnly; }
const Vector<KURL>& reportURIs() const { return m_reportURIs; }
private:
CSPDirectiveList(ContentSecurityPolicy*, ContentSecurityPolicyHeaderType, ContentSecurityPolicyHeaderSource);
bool parseDirective(const UChar* begin, const UChar* end, String& name, String& value);
void parseReportURI(const String& name, const String& value);
void parsePluginTypes(const String& name, const String& value);
void parseReflectedXSS(const String& name, const String& value);
void parseReferrer(const String& name, const String& value);
void addDirective(const String& name, const String& value);
void applySandboxPolicy(const String& name, const String& sandboxPolicy);
template <class CSPDirectiveType>
void setCSPDirective(const String& name, const String& value, OwnPtr<CSPDirectiveType>&);
SourceListDirective* operativeDirective(SourceListDirective*) const;
SourceListDirective* operativeDirective(SourceListDirective*, SourceListDirective* override) const;
void reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL) const;
void reportViolationWithLocation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const String& contextURL, const WTF::OrdinalNumber& contextLine) const;
void reportViolationWithState(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, ScriptState*) const;
bool checkEval(SourceListDirective*) const;
bool checkInline(SourceListDirective*) const;
bool checkNonce(SourceListDirective*, const String&) const;
bool checkHash(SourceListDirective*, const CSPHashValue&) const;
bool checkSource(SourceListDirective*, const KURL&) const;
bool checkMediaType(MediaListDirective*, const String& type, const String& typeAttribute) const;
bool checkAncestors(SourceListDirective*, LocalFrame*) const;
void setEvalDisabledErrorMessage(const String& errorMessage) { m_evalDisabledErrorMessage = errorMessage; }
bool checkEvalAndReportViolation(SourceListDirective*, const String& consoleMessage, ScriptState*) const;
bool checkInlineAndReportViolation(SourceListDirective*, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine, bool isScript) const;
bool checkSourceAndReportViolation(SourceListDirective*, const KURL&, const String& effectiveDirective) const;
bool checkMediaTypeAndReportViolation(MediaListDirective*, const String& type, const String& typeAttribute, const String& consoleMessage) const;
bool checkAncestorsAndReportViolation(SourceListDirective*, LocalFrame*) const;
bool denyIfEnforcingPolicy() const { return m_reportOnly; }
ContentSecurityPolicy* m_policy;
String m_header;
ContentSecurityPolicyHeaderType m_headerType;
ContentSecurityPolicyHeaderSource m_headerSource;
bool m_reportOnly;
bool m_haveSandboxPolicy;
ReflectedXSSDisposition m_reflectedXSSDisposition;
bool m_didSetReferrerPolicy;
ReferrerPolicy m_referrerPolicy;
OwnPtr<MediaListDirective> m_pluginTypes;
OwnPtr<SourceListDirective> m_baseURI;
OwnPtr<SourceListDirective> m_childSrc;
OwnPtr<SourceListDirective> m_connectSrc;
OwnPtr<SourceListDirective> m_defaultSrc;
OwnPtr<SourceListDirective> m_fontSrc;
OwnPtr<SourceListDirective> m_formAction;
OwnPtr<SourceListDirective> m_frameAncestors;
OwnPtr<SourceListDirective> m_frameSrc;
OwnPtr<SourceListDirective> m_imgSrc;
OwnPtr<SourceListDirective> m_mediaSrc;
OwnPtr<SourceListDirective> m_objectSrc;
OwnPtr<SourceListDirective> m_scriptSrc;
OwnPtr<SourceListDirective> m_styleSrc;
Vector<KURL> m_reportURIs;
String m_evalDisabledErrorMessage;
};
CSPDirectiveList::CSPDirectiveList(ContentSecurityPolicy* policy, ContentSecurityPolicyHeaderType type, ContentSecurityPolicyHeaderSource source)
: m_policy(policy)
, m_headerType(type)
, m_headerSource(source)
, m_reportOnly(false)
, m_haveSandboxPolicy(false)
, m_reflectedXSSDisposition(ReflectedXSSUnset)
, m_didSetReferrerPolicy(false)
, m_referrerPolicy(ReferrerPolicyDefault)
{
m_reportOnly = type == ContentSecurityPolicyHeaderTypeReport;
}
PassOwnPtr<CSPDirectiveList> CSPDirectiveList::create(ContentSecurityPolicy* policy, const UChar* begin, const UChar* end, ContentSecurityPolicyHeaderType type, ContentSecurityPolicyHeaderSource source)
{
OwnPtr<CSPDirectiveList> directives = adoptPtr(new CSPDirectiveList(policy, type, source));
directives->parse(begin, end);
if (!directives->checkEval(directives->operativeDirective(directives->m_scriptSrc.get()))) {
String message = "Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: \"" + directives->operativeDirective(directives->m_scriptSrc.get())->text() + "\".\n";
directives->setEvalDisabledErrorMessage(message);
}
if (directives->isReportOnly() && directives->reportURIs().isEmpty())
policy->reportMissingReportURI(String(begin, end - begin));
return directives.release();
}
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->client()->addConsoleMessage(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->client()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message, contextURL, contextLine.oneBasedInt());
m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportURIs, m_header);
}
void CSPDirectiveList::reportViolationWithState(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, ScriptState* state) const
{
String message = m_reportOnly ? "[Report Only] " + consoleMessage : consoleMessage;
m_policy->client()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message, state);
m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportURIs, m_header);
}
bool CSPDirectiveList::checkEval(SourceListDirective* directive) const
{
return !directive || directive->allowEval();
}
bool CSPDirectiveList::checkInline(SourceListDirective* directive) const
{
return !directive || (directive->allowInline() && !directive->isHashOrNoncePresent());
}
bool CSPDirectiveList::checkNonce(SourceListDirective* directive, const String& nonce) const
{
return !directive || directive->allowNonce(nonce);
}
bool CSPDirectiveList::checkHash(SourceListDirective* directive, const CSPHashValue& hashValue) const
{
return !directive || directive->allowHash(hashValue);
}
bool CSPDirectiveList::checkSource(SourceListDirective* directive, const KURL& url) const
{
return !directive || directive->allows(url);
}
bool CSPDirectiveList::checkAncestors(SourceListDirective* directive, LocalFrame* frame) const
{
if (!frame || !directive)
return true;
for (LocalFrame* current = frame->tree().parent(); current; current = current->tree().parent()) {
if (!directive->allows(current->document()->url()))
return false;
}
return true;
}
bool CSPDirectiveList::checkMediaType(MediaListDirective* directive, const String& type, const String& typeAttribute) const
{
if (!directive)
return true;
if (typeAttribute.isEmpty() || typeAttribute.stripWhiteSpace() != type)
return false;
return directive->allows(type);
}
SourceListDirective* CSPDirectiveList::operativeDirective(SourceListDirective* directive) const
{
return directive ? directive : m_defaultSrc.get();
}
SourceListDirective* CSPDirectiveList::operativeDirective(SourceListDirective* directive, SourceListDirective* override) const
{
return directive ? directive : override;
}
bool CSPDirectiveList::checkEvalAndReportViolation(SourceListDirective* directive, const String& consoleMessage, ScriptState* state) const
{
if (checkEval(directive))
return true;
String suffix = String();
if (directive == m_defaultSrc)
suffix = " Note that 'script-src' was not explicitly set, so 'default-src' is used as a fallback.";
reportViolationWithState(directive->text(), scriptSrc, consoleMessage + "\"" + directive->text() + "\"." + suffix + "\n", KURL(), state);
if (!m_reportOnly) {
m_policy->reportBlockedScriptExecutionToInspector(directive->text());
return false;
}
return true;
}
bool CSPDirectiveList::checkMediaTypeAndReportViolation(MediaListDirective* directive, const String& type, const String& typeAttribute, const String& consoleMessage) const
{
if (checkMediaType(directive, type, typeAttribute))
return true;
String message = consoleMessage + "\'" + directive->text() + "\'.";
if (typeAttribute.isEmpty())
message = message + " When enforcing the 'plugin-types' directive, the plugin's media type must be explicitly declared with a 'type' attribute on the containing element (e.g. '<object type=\"[TYPE GOES HERE]\" ...>').";
reportViolation(directive->text(), pluginTypes, message + "\n", KURL());
return denyIfEnforcingPolicy();
}
bool CSPDirectiveList::checkInlineAndReportViolation(SourceListDirective* directive, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine, bool isScript) const
{
if (checkInline(directive))
return true;
String suffix = String();
if (directive->allowInline() && directive->isHashOrNoncePresent()) {
// If inline is allowed, but a hash or nonce is present, we ignore 'unsafe-inline'. Throw a reasonable error.
suffix = " Note that 'unsafe-inline' is ignored if either a hash or nonce value is present in the source list.";
} else {
suffix = " Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.";
if (directive == m_defaultSrc)
suffix = suffix + " Note also that '" + String(isScript ? "script" : "style") + "-src' was not explicitly set, so 'default-src' is used as a fallback.";
}
reportViolationWithLocation(directive->text(), isScript ? scriptSrc : styleSrc, consoleMessage + "\"" + directive->text() + "\"." + suffix + "\n", KURL(), contextURL, contextLine);
if (!m_reportOnly) {
if (isScript)
m_policy->reportBlockedScriptExecutionToInspector(directive->text());
return false;
}
return true;
}
bool CSPDirectiveList::checkSourceAndReportViolation(SourceListDirective* directive, const KURL& url, const String& effectiveDirective) const
{
if (checkSource(directive, url))
return true;
String prefix;
if (baseURI == effectiveDirective)
prefix = "Refused to set the document's base URI to '";
else if (childSrc == effectiveDirective)
prefix = "Refused to create a child context containing '";
else if (connectSrc == effectiveDirective)
prefix = "Refused to connect to '";
else if (fontSrc == effectiveDirective)
prefix = "Refused to load the font '";
else if (formAction == effectiveDirective)
prefix = "Refused to send form data to '";
else if (frameSrc == effectiveDirective)
prefix = "Refused to frame '";
else if (imgSrc == effectiveDirective)
prefix = "Refused to load the image '";
else if (mediaSrc == effectiveDirective)
prefix = "Refused to load media from '";
else if (objectSrc == effectiveDirective)
prefix = "Refused to load plugin data from '";
else if (scriptSrc == effectiveDirective)
prefix = "Refused to load the script '";
else if (styleSrc == effectiveDirective)
prefix = "Refused to load the stylesheet '";
String suffix = String();
if (directive == m_defaultSrc)
suffix = " Note that '" + effectiveDirective + "' was not explicitly set, so 'default-src' is used as a fallback.";
reportViolation(directive->text(), effectiveDirective, prefix + url.elidedString() + "' because it violates the following Content Security Policy directive: \"" + directive->text() + "\"." + suffix + "\n", url);
return denyIfEnforcingPolicy();
}
bool CSPDirectiveList::checkAncestorsAndReportViolation(SourceListDirective* directive, LocalFrame* frame) const
{
if (checkAncestors(directive, frame))
return true;
reportViolation(directive->text(), "frame-ancestors", "Refused to display '" + frame->document()->url().elidedString() + " in a frame because an ancestor violates the following Content Security Policy directive: \"" + directive->text() + "\".", frame->document()->url());
return denyIfEnforcingPolicy();
}
bool CSPDirectiveList::allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute JavaScript URL because it violates the following Content Security Policy directive: "));
if (reportingStatus == ContentSecurityPolicy::SendReport)
return checkInlineAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, contextURL, contextLine, true);
return checkInline(operativeDirective(m_scriptSrc.get()));
}
bool CSPDirectiveList::allowInlineEventHandlers(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute inline event handler because it violates the following Content Security Policy directive: "));
if (reportingStatus == ContentSecurityPolicy::SendReport)
return checkInlineAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, contextURL, contextLine, true);
return checkInline(operativeDirective(m_scriptSrc.get()));
}
bool CSPDirectiveList::allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute inline script because it violates the following Content Security Policy directive: "));
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkInlineAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, contextURL, contextLine, true) :
checkInline(operativeDirective(m_scriptSrc.get()));
}
bool CSPDirectiveList::allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to apply inline style because it violates the following Content Security Policy directive: "));
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkInlineAndReportViolation(operativeDirective(m_styleSrc.get()), consoleMessage, contextURL, contextLine, false) :
checkInline(operativeDirective(m_styleSrc.get()));
}
bool CSPDirectiveList::allowEval(ScriptState* state, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "));
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkEvalAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, state) :
checkEval(operativeDirective(m_scriptSrc.get()));
}
bool CSPDirectiveList::allowPluginType(const String& type, const String& typeAttribute, const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkMediaTypeAndReportViolation(m_pluginTypes.get(), type, typeAttribute, "Refused to load '" + url.elidedString() + "' (MIME type '" + typeAttribute + "') because it violates the following Content Security Policy Directive: ") :
checkMediaType(m_pluginTypes.get(), type, typeAttribute);
}
bool CSPDirectiveList::allowScriptFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(operativeDirective(m_scriptSrc.get()), url, scriptSrc) :
checkSource(operativeDirective(m_scriptSrc.get()), url);
}
bool CSPDirectiveList::allowObjectFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
if (url.isBlankURL())
return true;
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(operativeDirective(m_objectSrc.get()), url, objectSrc) :
checkSource(operativeDirective(m_objectSrc.get()), url);
}
bool CSPDirectiveList::allowChildFrameFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
if (url.isBlankURL())
return true;
// 'frame-src' is the only directive which overrides something other than the default sources.
// It overrides 'child-src', which overrides the default sources. So, we do this nested set
// of calls to 'operativeDirective()' to grab 'frame-src' if it exists, 'child-src' if it
// doesn't, and 'defaut-src' if neither are available.
//
// All of this only applies, of course, if we're in CSP 1.1. In CSP 1.0, 'frame-src'
// overrides 'default-src' directly.
SourceListDirective* whichDirective = m_policy->experimentalFeaturesEnabled() ?
operativeDirective(m_frameSrc.get(), operativeDirective(m_childSrc.get())) :
operativeDirective(m_frameSrc.get());
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(whichDirective, url, frameSrc) :
checkSource(whichDirective, url);
}
bool CSPDirectiveList::allowImageFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(operativeDirective(m_imgSrc.get()), url, imgSrc) :
checkSource(operativeDirective(m_imgSrc.get()), url);
}
bool CSPDirectiveList::allowStyleFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(operativeDirective(m_styleSrc.get()), url, styleSrc) :
checkSource(operativeDirective(m_styleSrc.get()), url);
}
bool CSPDirectiveList::allowFontFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(operativeDirective(m_fontSrc.get()), url, fontSrc) :
checkSource(operativeDirective(m_fontSrc.get()), url);
}
bool CSPDirectiveList::allowMediaFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(operativeDirective(m_mediaSrc.get()), url, mediaSrc) :
checkSource(operativeDirective(m_mediaSrc.get()), url);
}
bool CSPDirectiveList::allowConnectToSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(operativeDirective(m_connectSrc.get()), url, connectSrc) :
checkSource(operativeDirective(m_connectSrc.get()), url);
}
bool CSPDirectiveList::allowFormAction(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(m_formAction.get(), url, formAction) :
checkSource(m_formAction.get(), url);
}
bool CSPDirectiveList::allowBaseURI(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(m_baseURI.get(), url, baseURI) :
checkSource(m_baseURI.get(), url);
}
bool CSPDirectiveList::allowAncestors(LocalFrame* frame, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkAncestorsAndReportViolation(m_frameAncestors.get(), frame) :
checkAncestors(m_frameAncestors.get(), frame);
}
bool CSPDirectiveList::allowChildContextFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(operativeDirective(m_childSrc.get()), url, childSrc) :
checkSource(operativeDirective(m_childSrc.get()), url);
}
bool CSPDirectiveList::allowScriptNonce(const String& nonce) const
{
return checkNonce(operativeDirective(m_scriptSrc.get()), nonce);
}
bool CSPDirectiveList::allowStyleNonce(const String& nonce) const
{
return checkNonce(operativeDirective(m_styleSrc.get()), nonce);
}
bool CSPDirectiveList::allowScriptHash(const CSPHashValue& hashValue) const
{
return checkHash(operativeDirective(m_scriptSrc.get()), hashValue);
}
bool CSPDirectiveList::allowStyleHash(const CSPHashValue& hashValue) const
{
return checkHash(operativeDirective(m_styleSrc.get()), hashValue);
}
// policy = directive-list
// directive-list = [ directive *( ";" [ directive ] ) ]
//
void CSPDirectiveList::parse(const UChar* begin, const UChar* end)
{
m_header = String(begin, end - begin);
if (begin == end)
return;
const UChar* position = begin;
while (position < end) {
const UChar* directiveBegin = position;
skipUntil<UChar>(position, end, ';');
String name, value;
if (parseDirective(directiveBegin, position, name, value)) {
ASSERT(!name.isEmpty());
addDirective(name, value);
}
ASSERT(position == end || *position == ';');
skipExactly<UChar>(position, end, ';');
}
}
// directive = *WSP [ directive-name [ WSP directive-value ] ]
// directive-name = 1*( ALPHA / DIGIT / "-" )
// directive-value = *( WSP / <VCHAR except ";"> )
//
bool CSPDirectiveList::parseDirective(const UChar* begin, const UChar* end, String& name, String& value)
{
ASSERT(name.isEmpty());
ASSERT(value.isEmpty());
const UChar* position = begin;
skipWhile<UChar, isASCIISpace>(position, end);
// Empty directive (e.g. ";;;"). Exit early.
if (position == end)
return false;
const UChar* nameBegin = position;
skipWhile<UChar, isCSPDirectiveNameCharacter>(position, end);
// The directive-name must be non-empty.
if (nameBegin == position) {
skipWhile<UChar, isNotASCIISpace>(position, end);
m_policy->reportUnsupportedDirective(String(nameBegin, position - nameBegin));
return false;
}
name = String(nameBegin, position - nameBegin);
if (position == end)
return true;
if (!skipExactly<UChar, isASCIISpace>(position, end)) {
skipWhile<UChar, isNotASCIISpace>(position, end);
m_policy->reportUnsupportedDirective(String(nameBegin, position - nameBegin));
return false;
}
skipWhile<UChar, isASCIISpace>(position, end);
const UChar* valueBegin = position;
skipWhile<UChar, isCSPDirectiveValueCharacter>(position, end);
if (position != end) {
m_policy->reportInvalidDirectiveValueCharacter(name, String(valueBegin, end - valueBegin));
return false;
}
// The directive-value may be empty.
if (valueBegin == position)
return true;
value = String(valueBegin, position - valueBegin);
return true;
}
void CSPDirectiveList::parseReportURI(const String& name, const String& value)
{
if (!m_reportURIs.isEmpty()) {
m_policy->reportDuplicateDirective(name);
return;
}
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* urlBegin = position;
skipWhile<UChar, isNotASCIISpace>(position, end);
if (urlBegin < position) {
String url = String(urlBegin, position - urlBegin);
m_reportURIs.append(m_policy->completeURL(url));
}
}
}
template<class CSPDirectiveType>
void CSPDirectiveList::setCSPDirective(const String& name, const String& value, OwnPtr<CSPDirectiveType>& directive)
{
if (directive) {
m_policy->reportDuplicateDirective(name);
return;
}
directive = adoptPtr(new CSPDirectiveType(name, value, m_policy));
}
void CSPDirectiveList::applySandboxPolicy(const String& name, const String& sandboxPolicy)
{
if (m_reportOnly) {
m_policy->reportInvalidInReportOnly(name);
return;
}
if (m_haveSandboxPolicy) {
m_policy->reportDuplicateDirective(name);
return;
}
m_haveSandboxPolicy = true;
String invalidTokens;
m_policy->enforceSandboxFlags(parseSandboxPolicy(sandboxPolicy, invalidTokens));
if (!invalidTokens.isNull())
m_policy->reportInvalidSandboxFlags(invalidTokens);
}
void CSPDirectiveList::parseReflectedXSS(const String& name, const String& value)
{
if (m_reflectedXSSDisposition != ReflectedXSSUnset) {
m_policy->reportDuplicateDirective(name);
m_reflectedXSSDisposition = ReflectedXSSInvalid;
return;
}
if (value.isEmpty()) {
m_reflectedXSSDisposition = ReflectedXSSInvalid;
m_policy->reportInvalidReflectedXSS(value);
return;
}
Vector<UChar> characters;
value.appendTo(characters);
const UChar* position = characters.data();
const UChar* end = position + characters.size();
skipWhile<UChar, isASCIISpace>(position, end);
const UChar* begin = position;
skipWhile<UChar, isNotASCIISpace>(position, end);
// value1
// ^
if (equalIgnoringCase("allow", begin, position - begin)) {
m_reflectedXSSDisposition = AllowReflectedXSS;
} else if (equalIgnoringCase("filter", begin, position - begin)) {
m_reflectedXSSDisposition = FilterReflectedXSS;
} else if (equalIgnoringCase("block", begin, position - begin)) {
m_reflectedXSSDisposition = BlockReflectedXSS;
} else {
m_reflectedXSSDisposition = ReflectedXSSInvalid;
m_policy->reportInvalidReflectedXSS(value);
return;
}
skipWhile<UChar, isASCIISpace>(position, end);
if (position == end && m_reflectedXSSDisposition != ReflectedXSSUnset)
return;
// value1 value2
// ^
m_reflectedXSSDisposition = ReflectedXSSInvalid;
m_policy->reportInvalidReflectedXSS(value);
}
void CSPDirectiveList::parseReferrer(const String& name, const String& value)
{
if (m_didSetReferrerPolicy) {
m_policy->reportDuplicateDirective(name);
m_referrerPolicy = ReferrerPolicyNever;
return;
}
m_didSetReferrerPolicy = true;
if (value.isEmpty()) {
m_policy->reportInvalidReferrer(value);
m_referrerPolicy = ReferrerPolicyNever;
return;
}
Vector<UChar> characters;
value.appendTo(characters);
const UChar* position = characters.data();
const UChar* end = position + characters.size();
skipWhile<UChar, isASCIISpace>(position, end);
const UChar* begin = position;
skipWhile<UChar, isNotASCIISpace>(position, end);
// value1
// ^
if (equalIgnoringCase("always", begin, position - begin)) {
m_referrerPolicy = ReferrerPolicyAlways;
} else if (equalIgnoringCase("default", begin, position - begin)) {
m_referrerPolicy = ReferrerPolicyDefault;
} else if (equalIgnoringCase("never", begin, position - begin)) {
m_referrerPolicy = ReferrerPolicyNever;
} else if (equalIgnoringCase("origin", begin, position - begin)) {
m_referrerPolicy = ReferrerPolicyOrigin;
} else {
m_referrerPolicy = ReferrerPolicyNever;
m_policy->reportInvalidReferrer(value);
return;
}
skipWhile<UChar, isASCIISpace>(position, end);
if (position == end)
return;
// value1 value2
// ^
m_referrerPolicy = ReferrerPolicyNever;
m_policy->reportInvalidReferrer(value);
}
void CSPDirectiveList::addDirective(const String& name, const String& value)
{
ASSERT(!name.isEmpty());
if (equalIgnoringCase(name, defaultSrc)) {
setCSPDirective<SourceListDirective>(name, value, m_defaultSrc);
} else if (equalIgnoringCase(name, scriptSrc)) {
setCSPDirective<SourceListDirective>(name, value, m_scriptSrc);
m_policy->usesScriptHashAlgorithms(m_scriptSrc->hashAlgorithmsUsed());
} else if (equalIgnoringCase(name, objectSrc)) {
setCSPDirective<SourceListDirective>(name, value, m_objectSrc);
} else if (equalIgnoringCase(name, frameSrc)) {
setCSPDirective<SourceListDirective>(name, value, m_frameSrc);
} else if (equalIgnoringCase(name, imgSrc)) {
setCSPDirective<SourceListDirective>(name, value, m_imgSrc);
} else if (equalIgnoringCase(name, styleSrc)) {
setCSPDirective<SourceListDirective>(name, value, m_styleSrc);
m_policy->usesStyleHashAlgorithms(m_styleSrc->hashAlgorithmsUsed());
} else if (equalIgnoringCase(name, fontSrc)) {
setCSPDirective<SourceListDirective>(name, value, m_fontSrc);
} else if (equalIgnoringCase(name, mediaSrc)) {
setCSPDirective<SourceListDirective>(name, value, m_mediaSrc);
} else if (equalIgnoringCase(name, connectSrc)) {
setCSPDirective<SourceListDirective>(name, value, m_connectSrc);
} else if (equalIgnoringCase(name, sandbox)) {
applySandboxPolicy(name, value);
} else if (equalIgnoringCase(name, reportURI)) {
parseReportURI(name, value);
} else if (m_policy->experimentalFeaturesEnabled()) {
if (equalIgnoringCase(name, baseURI))
setCSPDirective<SourceListDirective>(name, value, m_baseURI);
else if (equalIgnoringCase(name, childSrc))
setCSPDirective<SourceListDirective>(name, value, m_childSrc);
else if (equalIgnoringCase(name, formAction))
setCSPDirective<SourceListDirective>(name, value, m_formAction);
else if (equalIgnoringCase(name, frameAncestors))
setCSPDirective<SourceListDirective>(name, value, m_frameAncestors);
else if (equalIgnoringCase(name, pluginTypes))
setCSPDirective<MediaListDirective>(name, value, m_pluginTypes);
else if (equalIgnoringCase(name, reflectedXSS))
parseReflectedXSS(name, value);
else if (equalIgnoringCase(name, referrer))
parseReferrer(name, value);
else
m_policy->reportUnsupportedDirective(name);
} else {
m_policy->reportUnsupportedDirective(name);
}
}
ContentSecurityPolicy::ContentSecurityPolicy(ExecutionContextClient* client) ContentSecurityPolicy::ContentSecurityPolicy(ExecutionContextClient* client)
: m_client(client) : m_client(client)
, m_overrideInlineStyleAllowed(false) , m_overrideInlineStyleAllowed(false)
......
...@@ -60,6 +60,28 @@ typedef Vector<OwnPtr<CSPDirectiveList> > CSPDirectiveListVector; ...@@ -60,6 +60,28 @@ typedef Vector<OwnPtr<CSPDirectiveList> > CSPDirectiveListVector;
class ContentSecurityPolicy : public RefCounted<ContentSecurityPolicy> { class ContentSecurityPolicy : public RefCounted<ContentSecurityPolicy> {
WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_FAST_ALLOCATED;
public: public:
// CSP 1.0 Directives
static const char ConnectSrc[];
static const char DefaultSrc[];
static const char FontSrc[];
static const char FrameSrc[];
static const char ImgSrc[];
static const char MediaSrc[];
static const char ObjectSrc[];
static const char ReportURI[];
static const char Sandbox[];
static const char ScriptSrc[];
static const char StyleSrc[];
// CSP 1.1 Directives
static const char BaseURI[];
static const char ChildSrc[];
static const char FormAction[];
static const char FrameAncestors[];
static const char PluginTypes[];
static const char ReflectedXSS[];
static const char Referrer[];
static PassRefPtr<ContentSecurityPolicy> create(ExecutionContextClient* client) static PassRefPtr<ContentSecurityPolicy> create(ExecutionContextClient* client)
{ {
return adoptRef(new ContentSecurityPolicy(client)); return adoptRef(new ContentSecurityPolicy(client));
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include "core/frame/csp/CSPDirectiveList.h"
#include "core/frame/LocalFrame.h"
#include "platform/ParsingUtilities.h"
#include "platform/weborigin/KURL.h"
#include "wtf/text/WTFString.h"
namespace WebCore {
CSPDirectiveList::CSPDirectiveList(ContentSecurityPolicy* policy, ContentSecurityPolicyHeaderType type, ContentSecurityPolicyHeaderSource source)
: m_policy(policy)
, m_headerType(type)
, m_headerSource(source)
, m_reportOnly(false)
, m_haveSandboxPolicy(false)
, m_reflectedXSSDisposition(ReflectedXSSUnset)
, m_didSetReferrerPolicy(false)
, m_referrerPolicy(ReferrerPolicyDefault)
{
m_reportOnly = type == ContentSecurityPolicyHeaderTypeReport;
}
PassOwnPtr<CSPDirectiveList> CSPDirectiveList::create(ContentSecurityPolicy* policy, const UChar* begin, const UChar* end, ContentSecurityPolicyHeaderType type, ContentSecurityPolicyHeaderSource source)
{
OwnPtr<CSPDirectiveList> directives = adoptPtr(new CSPDirectiveList(policy, type, source));
directives->parse(begin, end);
if (!directives->checkEval(directives->operativeDirective(directives->m_scriptSrc.get()))) {
String message = "Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: \"" + directives->operativeDirective(directives->m_scriptSrc.get())->text() + "\".\n";
directives->setEvalDisabledErrorMessage(message);
}
if (directives->isReportOnly() && directives->reportURIs().isEmpty())
policy->reportMissingReportURI(String(begin, end - begin));
return directives.release();
}
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->client()->addConsoleMessage(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->client()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message, contextURL, contextLine.oneBasedInt());
m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportURIs, m_header);
}
void CSPDirectiveList::reportViolationWithState(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, ScriptState* state) const
{
String message = m_reportOnly ? "[Report Only] " + consoleMessage : consoleMessage;
m_policy->client()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message, state);
m_policy->reportViolation(directiveText, effectiveDirective, message, blockedURL, m_reportURIs, m_header);
}
bool CSPDirectiveList::checkEval(SourceListDirective* directive) const
{
return !directive || directive->allowEval();
}
bool CSPDirectiveList::checkInline(SourceListDirective* directive) const
{
return !directive || (directive->allowInline() && !directive->isHashOrNoncePresent());
}
bool CSPDirectiveList::checkNonce(SourceListDirective* directive, const String& nonce) const
{
return !directive || directive->allowNonce(nonce);
}
bool CSPDirectiveList::checkHash(SourceListDirective* directive, const CSPHashValue& hashValue) const
{
return !directive || directive->allowHash(hashValue);
}
bool CSPDirectiveList::checkSource(SourceListDirective* directive, const KURL& url) const
{
return !directive || directive->allows(url);
}
bool CSPDirectiveList::checkAncestors(SourceListDirective* directive, LocalFrame* frame) const
{
if (!frame || !directive)
return true;
for (LocalFrame* current = frame->tree().parent(); current; current = current->tree().parent()) {
if (!directive->allows(current->document()->url()))
return false;
}
return true;
}
bool CSPDirectiveList::checkMediaType(MediaListDirective* directive, const String& type, const String& typeAttribute) const
{
if (!directive)
return true;
if (typeAttribute.isEmpty() || typeAttribute.stripWhiteSpace() != type)
return false;
return directive->allows(type);
}
SourceListDirective* CSPDirectiveList::operativeDirective(SourceListDirective* directive) const
{
return directive ? directive : m_defaultSrc.get();
}
SourceListDirective* CSPDirectiveList::operativeDirective(SourceListDirective* directive, SourceListDirective* override) const
{
return directive ? directive : override;
}
bool CSPDirectiveList::checkEvalAndReportViolation(SourceListDirective* directive, const String& consoleMessage, ScriptState* state) const
{
if (checkEval(directive))
return true;
String suffix = String();
if (directive == m_defaultSrc)
suffix = " Note that 'script-src' was not explicitly set, so 'default-src' is used as a fallback.";
reportViolationWithState(directive->text(), ContentSecurityPolicy::ScriptSrc, consoleMessage + "\"" + directive->text() + "\"." + suffix + "\n", KURL(), state);
if (!m_reportOnly) {
m_policy->reportBlockedScriptExecutionToInspector(directive->text());
return false;
}
return true;
}
bool CSPDirectiveList::checkMediaTypeAndReportViolation(MediaListDirective* directive, const String& type, const String& typeAttribute, const String& consoleMessage) const
{
if (checkMediaType(directive, type, typeAttribute))
return true;
String message = consoleMessage + "\'" + directive->text() + "\'.";
if (typeAttribute.isEmpty())
message = message + " When enforcing the 'plugin-types' directive, the plugin's media type must be explicitly declared with a 'type' attribute on the containing element (e.g. '<object type=\"[TYPE GOES HERE]\" ...>').";
reportViolation(directive->text(), ContentSecurityPolicy::PluginTypes, message + "\n", KURL());
return denyIfEnforcingPolicy();
}
bool CSPDirectiveList::checkInlineAndReportViolation(SourceListDirective* directive, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine, bool isScript) const
{
if (checkInline(directive))
return true;
String suffix = String();
if (directive->allowInline() && directive->isHashOrNoncePresent()) {
// If inline is allowed, but a hash or nonce is present, we ignore 'unsafe-inline'. Throw a reasonable error.
suffix = " Note that 'unsafe-inline' is ignored if either a hash or nonce value is present in the source list.";
} else {
suffix = " Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.";
if (directive == m_defaultSrc)
suffix = suffix + " Note also that '" + String(isScript ? "script" : "style") + "-src' was not explicitly set, so 'default-src' is used as a fallback.";
}
reportViolationWithLocation(directive->text(), isScript ? ContentSecurityPolicy::ScriptSrc : ContentSecurityPolicy::StyleSrc, consoleMessage + "\"" + directive->text() + "\"." + suffix + "\n", KURL(), contextURL, contextLine);
if (!m_reportOnly) {
if (isScript)
m_policy->reportBlockedScriptExecutionToInspector(directive->text());
return false;
}
return true;
}
bool CSPDirectiveList::checkSourceAndReportViolation(SourceListDirective* directive, const KURL& url, const String& effectiveDirective) const
{
if (checkSource(directive, url))
return true;
String prefix;
if (ContentSecurityPolicy::BaseURI == effectiveDirective)
prefix = "Refused to set the document's base URI to '";
else if (ContentSecurityPolicy::ChildSrc == effectiveDirective)
prefix = "Refused to create a child context containing '";
else if (ContentSecurityPolicy::ConnectSrc == effectiveDirective)
prefix = "Refused to connect to '";
else if (ContentSecurityPolicy::FontSrc == effectiveDirective)
prefix = "Refused to load the font '";
else if (ContentSecurityPolicy::FormAction == effectiveDirective)
prefix = "Refused to send form data to '";
else if (ContentSecurityPolicy::FrameSrc == effectiveDirective)
prefix = "Refused to frame '";
else if (ContentSecurityPolicy::ImgSrc == effectiveDirective)
prefix = "Refused to load the image '";
else if (ContentSecurityPolicy::MediaSrc == effectiveDirective)
prefix = "Refused to load media from '";
else if (ContentSecurityPolicy::ObjectSrc == effectiveDirective)
prefix = "Refused to load plugin data from '";
else if (ContentSecurityPolicy::ScriptSrc == effectiveDirective)
prefix = "Refused to load the script '";
else if (ContentSecurityPolicy::StyleSrc == effectiveDirective)
prefix = "Refused to load the stylesheet '";
String suffix = String();
if (directive == m_defaultSrc)
suffix = " Note that '" + effectiveDirective + "' was not explicitly set, so 'default-src' is used as a fallback.";
reportViolation(directive->text(), effectiveDirective, prefix + url.elidedString() + "' because it violates the following Content Security Policy directive: \"" + directive->text() + "\"." + suffix + "\n", url);
return denyIfEnforcingPolicy();
}
bool CSPDirectiveList::checkAncestorsAndReportViolation(SourceListDirective* directive, LocalFrame* frame) const
{
if (checkAncestors(directive, frame))
return true;
reportViolation(directive->text(), "frame-ancestors", "Refused to display '" + frame->document()->url().elidedString() + " in a frame because an ancestor violates the following Content Security Policy directive: \"" + directive->text() + "\".", frame->document()->url());
return denyIfEnforcingPolicy();
}
bool CSPDirectiveList::allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute JavaScript URL because it violates the following Content Security Policy directive: "));
if (reportingStatus == ContentSecurityPolicy::SendReport)
return checkInlineAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, contextURL, contextLine, true);
return checkInline(operativeDirective(m_scriptSrc.get()));
}
bool CSPDirectiveList::allowInlineEventHandlers(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute inline event handler because it violates the following Content Security Policy directive: "));
if (reportingStatus == ContentSecurityPolicy::SendReport)
return checkInlineAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, contextURL, contextLine, true);
return checkInline(operativeDirective(m_scriptSrc.get()));
}
bool CSPDirectiveList::allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute inline script because it violates the following Content Security Policy directive: "));
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkInlineAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, contextURL, contextLine, true) :
checkInline(operativeDirective(m_scriptSrc.get()));
}
bool CSPDirectiveList::allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to apply inline style because it violates the following Content Security Policy directive: "));
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkInlineAndReportViolation(operativeDirective(m_styleSrc.get()), consoleMessage, contextURL, contextLine, false) :
checkInline(operativeDirective(m_styleSrc.get()));
}
bool CSPDirectiveList::allowEval(ScriptState* state, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "));
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkEvalAndReportViolation(operativeDirective(m_scriptSrc.get()), consoleMessage, state) :
checkEval(operativeDirective(m_scriptSrc.get()));
}
bool CSPDirectiveList::allowPluginType(const String& type, const String& typeAttribute, const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkMediaTypeAndReportViolation(m_pluginTypes.get(), type, typeAttribute, "Refused to load '" + url.elidedString() + "' (MIME type '" + typeAttribute + "') because it violates the following Content Security Policy Directive: ") :
checkMediaType(m_pluginTypes.get(), type, typeAttribute);
}
bool CSPDirectiveList::allowScriptFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(operativeDirective(m_scriptSrc.get()), url, ContentSecurityPolicy::ScriptSrc) :
checkSource(operativeDirective(m_scriptSrc.get()), url);
}
bool CSPDirectiveList::allowObjectFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
if (url.isBlankURL())
return true;
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(operativeDirective(m_objectSrc.get()), url, ContentSecurityPolicy::ObjectSrc) :
checkSource(operativeDirective(m_objectSrc.get()), url);
}
bool CSPDirectiveList::allowChildFrameFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
if (url.isBlankURL())
return true;
// 'frame-src' is the only directive which overrides something other than the default sources.
// It overrides 'child-src', which overrides the default sources. So, we do this nested set
// of calls to 'operativeDirective()' to grab 'frame-src' if it exists, 'child-src' if it
// doesn't, and 'defaut-src' if neither are available.
//
// All of this only applies, of course, if we're in CSP 1.1. In CSP 1.0, 'frame-src'
// overrides 'default-src' directly.
SourceListDirective* whichDirective = m_policy->experimentalFeaturesEnabled() ?
operativeDirective(m_frameSrc.get(), operativeDirective(m_childSrc.get())) :
operativeDirective(m_frameSrc.get());
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(whichDirective, url, ContentSecurityPolicy::FrameSrc) :
checkSource(whichDirective, url);
}
bool CSPDirectiveList::allowImageFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(operativeDirective(m_imgSrc.get()), url, ContentSecurityPolicy::ImgSrc) :
checkSource(operativeDirective(m_imgSrc.get()), url);
}
bool CSPDirectiveList::allowStyleFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(operativeDirective(m_styleSrc.get()), url, ContentSecurityPolicy::StyleSrc) :
checkSource(operativeDirective(m_styleSrc.get()), url);
}
bool CSPDirectiveList::allowFontFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(operativeDirective(m_fontSrc.get()), url, ContentSecurityPolicy::FontSrc) :
checkSource(operativeDirective(m_fontSrc.get()), url);
}
bool CSPDirectiveList::allowMediaFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(operativeDirective(m_mediaSrc.get()), url, ContentSecurityPolicy::MediaSrc) :
checkSource(operativeDirective(m_mediaSrc.get()), url);
}
bool CSPDirectiveList::allowConnectToSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(operativeDirective(m_connectSrc.get()), url, ContentSecurityPolicy::ConnectSrc) :
checkSource(operativeDirective(m_connectSrc.get()), url);
}
bool CSPDirectiveList::allowFormAction(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(m_formAction.get(), url, ContentSecurityPolicy::FormAction) :
checkSource(m_formAction.get(), url);
}
bool CSPDirectiveList::allowBaseURI(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(m_baseURI.get(), url, ContentSecurityPolicy::BaseURI) :
checkSource(m_baseURI.get(), url);
}
bool CSPDirectiveList::allowAncestors(LocalFrame* frame, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkAncestorsAndReportViolation(m_frameAncestors.get(), frame) :
checkAncestors(m_frameAncestors.get(), frame);
}
bool CSPDirectiveList::allowChildContextFromSource(const KURL& url, ContentSecurityPolicy::ReportingStatus reportingStatus) const
{
return reportingStatus == ContentSecurityPolicy::SendReport ?
checkSourceAndReportViolation(operativeDirective(m_childSrc.get()), url, ContentSecurityPolicy::ChildSrc) :
checkSource(operativeDirective(m_childSrc.get()), url);
}
bool CSPDirectiveList::allowScriptNonce(const String& nonce) const
{
return checkNonce(operativeDirective(m_scriptSrc.get()), nonce);
}
bool CSPDirectiveList::allowStyleNonce(const String& nonce) const
{
return checkNonce(operativeDirective(m_styleSrc.get()), nonce);
}
bool CSPDirectiveList::allowScriptHash(const CSPHashValue& hashValue) const
{
return checkHash(operativeDirective(m_scriptSrc.get()), hashValue);
}
bool CSPDirectiveList::allowStyleHash(const CSPHashValue& hashValue) const
{
return checkHash(operativeDirective(m_styleSrc.get()), hashValue);
}
// policy = directive-list
// directive-list = [ directive *( ";" [ directive ] ) ]
//
void CSPDirectiveList::parse(const UChar* begin, const UChar* end)
{
m_header = String(begin, end - begin);
if (begin == end)
return;
const UChar* position = begin;
while (position < end) {
const UChar* directiveBegin = position;
skipUntil<UChar>(position, end, ';');
String name, value;
if (parseDirective(directiveBegin, position, name, value)) {
ASSERT(!name.isEmpty());
addDirective(name, value);
}
ASSERT(position == end || *position == ';');
skipExactly<UChar>(position, end, ';');
}
}
// directive = *WSP [ directive-name [ WSP directive-value ] ]
// directive-name = 1*( ALPHA / DIGIT / "-" )
// directive-value = *( WSP / <VCHAR except ";"> )
//
bool CSPDirectiveList::parseDirective(const UChar* begin, const UChar* end, String& name, String& value)
{
ASSERT(name.isEmpty());
ASSERT(value.isEmpty());
const UChar* position = begin;
skipWhile<UChar, isASCIISpace>(position, end);
// Empty directive (e.g. ";;;"). Exit early.
if (position == end)
return false;
const UChar* nameBegin = position;
skipWhile<UChar, isCSPDirectiveNameCharacter>(position, end);
// The directive-name must be non-empty.
if (nameBegin == position) {
skipWhile<UChar, isNotASCIISpace>(position, end);
m_policy->reportUnsupportedDirective(String(nameBegin, position - nameBegin));
return false;
}
name = String(nameBegin, position - nameBegin);
if (position == end)
return true;
if (!skipExactly<UChar, isASCIISpace>(position, end)) {
skipWhile<UChar, isNotASCIISpace>(position, end);
m_policy->reportUnsupportedDirective(String(nameBegin, position - nameBegin));
return false;
}
skipWhile<UChar, isASCIISpace>(position, end);
const UChar* valueBegin = position;
skipWhile<UChar, isCSPDirectiveValueCharacter>(position, end);
if (position != end) {
m_policy->reportInvalidDirectiveValueCharacter(name, String(valueBegin, end - valueBegin));
return false;
}
// The directive-value may be empty.
if (valueBegin == position)
return true;
value = String(valueBegin, position - valueBegin);
return true;
}
void CSPDirectiveList::parseReportURI(const String& name, const String& value)
{
if (!m_reportURIs.isEmpty()) {
m_policy->reportDuplicateDirective(name);
return;
}
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* urlBegin = position;
skipWhile<UChar, isNotASCIISpace>(position, end);
if (urlBegin < position) {
String url = String(urlBegin, position - urlBegin);
m_reportURIs.append(m_policy->completeURL(url));
}
}
}
template<class CSPDirectiveType>
void CSPDirectiveList::setCSPDirective(const String& name, const String& value, OwnPtr<CSPDirectiveType>& directive)
{
if (directive) {
m_policy->reportDuplicateDirective(name);
return;
}
directive = adoptPtr(new CSPDirectiveType(name, value, m_policy));
}
void CSPDirectiveList::applySandboxPolicy(const String& name, const String& sandboxPolicy)
{
if (m_reportOnly) {
m_policy->reportInvalidInReportOnly(name);
return;
}
if (m_haveSandboxPolicy) {
m_policy->reportDuplicateDirective(name);
return;
}
m_haveSandboxPolicy = true;
String invalidTokens;
m_policy->enforceSandboxFlags(parseSandboxPolicy(sandboxPolicy, invalidTokens));
if (!invalidTokens.isNull())
m_policy->reportInvalidSandboxFlags(invalidTokens);
}
void CSPDirectiveList::parseReflectedXSS(const String& name, const String& value)
{
if (m_reflectedXSSDisposition != ReflectedXSSUnset) {
m_policy->reportDuplicateDirective(name);
m_reflectedXSSDisposition = ReflectedXSSInvalid;
return;
}
if (value.isEmpty()) {
m_reflectedXSSDisposition = ReflectedXSSInvalid;
m_policy->reportInvalidReflectedXSS(value);
return;
}
Vector<UChar> characters;
value.appendTo(characters);
const UChar* position = characters.data();
const UChar* end = position + characters.size();
skipWhile<UChar, isASCIISpace>(position, end);
const UChar* begin = position;
skipWhile<UChar, isNotASCIISpace>(position, end);
// value1
// ^
if (equalIgnoringCase("allow", begin, position - begin)) {
m_reflectedXSSDisposition = AllowReflectedXSS;
} else if (equalIgnoringCase("filter", begin, position - begin)) {
m_reflectedXSSDisposition = FilterReflectedXSS;
} else if (equalIgnoringCase("block", begin, position - begin)) {
m_reflectedXSSDisposition = BlockReflectedXSS;
} else {
m_reflectedXSSDisposition = ReflectedXSSInvalid;
m_policy->reportInvalidReflectedXSS(value);
return;
}
skipWhile<UChar, isASCIISpace>(position, end);
if (position == end && m_reflectedXSSDisposition != ReflectedXSSUnset)
return;
// value1 value2
// ^
m_reflectedXSSDisposition = ReflectedXSSInvalid;
m_policy->reportInvalidReflectedXSS(value);
}
void CSPDirectiveList::parseReferrer(const String& name, const String& value)
{
if (m_didSetReferrerPolicy) {
m_policy->reportDuplicateDirective(name);
m_referrerPolicy = ReferrerPolicyNever;
return;
}
m_didSetReferrerPolicy = true;
if (value.isEmpty()) {
m_policy->reportInvalidReferrer(value);
m_referrerPolicy = ReferrerPolicyNever;
return;
}
Vector<UChar> characters;
value.appendTo(characters);
const UChar* position = characters.data();
const UChar* end = position + characters.size();
skipWhile<UChar, isASCIISpace>(position, end);
const UChar* begin = position;
skipWhile<UChar, isNotASCIISpace>(position, end);
// value1
// ^
if (equalIgnoringCase("always", begin, position - begin)) {
m_referrerPolicy = ReferrerPolicyAlways;
} else if (equalIgnoringCase("default", begin, position - begin)) {
m_referrerPolicy = ReferrerPolicyDefault;
} else if (equalIgnoringCase("never", begin, position - begin)) {
m_referrerPolicy = ReferrerPolicyNever;
} else if (equalIgnoringCase("origin", begin, position - begin)) {
m_referrerPolicy = ReferrerPolicyOrigin;
} else {
m_referrerPolicy = ReferrerPolicyNever;
m_policy->reportInvalidReferrer(value);
return;
}
skipWhile<UChar, isASCIISpace>(position, end);
if (position == end)
return;
// value1 value2
// ^
m_referrerPolicy = ReferrerPolicyNever;
m_policy->reportInvalidReferrer(value);
}
void CSPDirectiveList::addDirective(const String& name, const String& value)
{
ASSERT(!name.isEmpty());
if (equalIgnoringCase(name, ContentSecurityPolicy::DefaultSrc)) {
setCSPDirective<SourceListDirective>(name, value, m_defaultSrc);
} else if (equalIgnoringCase(name, ContentSecurityPolicy::ScriptSrc)) {
setCSPDirective<SourceListDirective>(name, value, m_scriptSrc);
m_policy->usesScriptHashAlgorithms(m_scriptSrc->hashAlgorithmsUsed());
} else if (equalIgnoringCase(name, ContentSecurityPolicy::ObjectSrc)) {
setCSPDirective<SourceListDirective>(name, value, m_objectSrc);
} else if (equalIgnoringCase(name, ContentSecurityPolicy::FrameSrc)) {
setCSPDirective<SourceListDirective>(name, value, m_frameSrc);
} else if (equalIgnoringCase(name, ContentSecurityPolicy::ImgSrc)) {
setCSPDirective<SourceListDirective>(name, value, m_imgSrc);
} else if (equalIgnoringCase(name, ContentSecurityPolicy::StyleSrc)) {
setCSPDirective<SourceListDirective>(name, value, m_styleSrc);
m_policy->usesStyleHashAlgorithms(m_styleSrc->hashAlgorithmsUsed());
} else if (equalIgnoringCase(name, ContentSecurityPolicy::FontSrc)) {
setCSPDirective<SourceListDirective>(name, value, m_fontSrc);
} else if (equalIgnoringCase(name, ContentSecurityPolicy::MediaSrc)) {
setCSPDirective<SourceListDirective>(name, value, m_mediaSrc);
} else if (equalIgnoringCase(name, ContentSecurityPolicy::ConnectSrc)) {
setCSPDirective<SourceListDirective>(name, value, m_connectSrc);
} else if (equalIgnoringCase(name, ContentSecurityPolicy::Sandbox)) {
applySandboxPolicy(name, value);
} else if (equalIgnoringCase(name, ContentSecurityPolicy::ReportURI)) {
parseReportURI(name, value);
} else if (m_policy->experimentalFeaturesEnabled()) {
if (equalIgnoringCase(name, ContentSecurityPolicy::BaseURI))
setCSPDirective<SourceListDirective>(name, value, m_baseURI);
else if (equalIgnoringCase(name, ContentSecurityPolicy::ChildSrc))
setCSPDirective<SourceListDirective>(name, value, m_childSrc);
else if (equalIgnoringCase(name, ContentSecurityPolicy::FormAction))
setCSPDirective<SourceListDirective>(name, value, m_formAction);
else if (equalIgnoringCase(name, ContentSecurityPolicy::FrameAncestors))
setCSPDirective<SourceListDirective>(name, value, m_frameAncestors);
else if (equalIgnoringCase(name, ContentSecurityPolicy::PluginTypes))
setCSPDirective<MediaListDirective>(name, value, m_pluginTypes);
else if (equalIgnoringCase(name, ContentSecurityPolicy::ReflectedXSS))
parseReflectedXSS(name, value);
else if (equalIgnoringCase(name, ContentSecurityPolicy::Referrer))
parseReferrer(name, value);
else
m_policy->reportUnsupportedDirective(name);
} else {
m_policy->reportUnsupportedDirective(name);
}
}
} // namespace WebCore
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CSPDirectiveList_h
#define CSPDirectiveList_h
#include "core/frame/ContentSecurityPolicy.h"
#include "core/frame/csp/MediaListDirective.h"
#include "core/frame/csp/SourceListDirective.h"
#include "platform/network/ContentSecurityPolicyParsers.h"
#include "platform/network/HTTPParsers.h"
#include "platform/weborigin/KURL.h"
#include "platform/weborigin/ReferrerPolicy.h"
#include "wtf/OwnPtr.h"
#include "wtf/Vector.h"
#include "wtf/text/WTFString.h"
namespace WebCore {
class ContentSecurityPolicy;
class CSPDirectiveList {
WTF_MAKE_FAST_ALLOCATED;
WTF_MAKE_NONCOPYABLE(CSPDirectiveList);
public:
static PassOwnPtr<CSPDirectiveList> create(ContentSecurityPolicy*, const UChar* begin, const UChar* end, ContentSecurityPolicyHeaderType, ContentSecurityPolicyHeaderSource);
void parse(const UChar* begin, const UChar* end);
const String& header() const { return m_header; }
ContentSecurityPolicyHeaderType headerType() const { return m_headerType; }
ContentSecurityPolicyHeaderSource headerSource() const { return m_headerSource; }
bool allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
bool allowInlineEventHandlers(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
bool allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
bool allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus) const;
bool allowEval(ScriptState*, ContentSecurityPolicy::ReportingStatus) const;
bool allowPluginType(const String& type, const String& typeAttribute, const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowScriptFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowObjectFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowChildFrameFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowImageFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowStyleFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowFontFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowMediaFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowConnectToSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowFormAction(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowBaseURI(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowAncestors(LocalFrame*, ContentSecurityPolicy::ReportingStatus) const;
bool allowChildContextFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const;
bool allowScriptNonce(const String&) const;
bool allowStyleNonce(const String&) const;
bool allowScriptHash(const CSPHashValue&) const;
bool allowStyleHash(const CSPHashValue&) const;
const String& evalDisabledErrorMessage() const { return m_evalDisabledErrorMessage; }
ReflectedXSSDisposition reflectedXSSDisposition() const { return m_reflectedXSSDisposition; }
ReferrerPolicy referrerPolicy() const { return m_referrerPolicy; }
bool didSetReferrerPolicy() const { return m_didSetReferrerPolicy; }
bool isReportOnly() const { return m_reportOnly; }
const Vector<KURL>& reportURIs() const { return m_reportURIs; }
private:
CSPDirectiveList(ContentSecurityPolicy*, ContentSecurityPolicyHeaderType, ContentSecurityPolicyHeaderSource);
bool parseDirective(const UChar* begin, const UChar* end, String& name, String& value);
void parseReportURI(const String& name, const String& value);
void parsePluginTypes(const String& name, const String& value);
void parseReflectedXSS(const String& name, const String& value);
void parseReferrer(const String& name, const String& value);
void addDirective(const String& name, const String& value);
void applySandboxPolicy(const String& name, const String& sandboxPolicy);
template <class CSPDirectiveType>
void setCSPDirective(const String& name, const String& value, OwnPtr<CSPDirectiveType>&);
SourceListDirective* operativeDirective(SourceListDirective*) const;
SourceListDirective* operativeDirective(SourceListDirective*, SourceListDirective* override) const;
void reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL) const;
void reportViolationWithLocation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const String& contextURL, const WTF::OrdinalNumber& contextLine) const;
void reportViolationWithState(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, ScriptState*) const;
bool checkEval(SourceListDirective*) const;
bool checkInline(SourceListDirective*) const;
bool checkNonce(SourceListDirective*, const String&) const;
bool checkHash(SourceListDirective*, const CSPHashValue&) const;
bool checkSource(SourceListDirective*, const KURL&) const;
bool checkMediaType(MediaListDirective*, const String& type, const String& typeAttribute) const;
bool checkAncestors(SourceListDirective*, LocalFrame*) const;
void setEvalDisabledErrorMessage(const String& errorMessage) { m_evalDisabledErrorMessage = errorMessage; }
bool checkEvalAndReportViolation(SourceListDirective*, const String& consoleMessage, ScriptState*) const;
bool checkInlineAndReportViolation(SourceListDirective*, const String& consoleMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine, bool isScript) const;
bool checkSourceAndReportViolation(SourceListDirective*, const KURL&, const String& effectiveDirective) const;
bool checkMediaTypeAndReportViolation(MediaListDirective*, const String& type, const String& typeAttribute, const String& consoleMessage) const;
bool checkAncestorsAndReportViolation(SourceListDirective*, LocalFrame*) const;
bool denyIfEnforcingPolicy() const { return m_reportOnly; }
ContentSecurityPolicy* m_policy;
String m_header;
ContentSecurityPolicyHeaderType m_headerType;
ContentSecurityPolicyHeaderSource m_headerSource;
bool m_reportOnly;
bool m_haveSandboxPolicy;
ReflectedXSSDisposition m_reflectedXSSDisposition;
bool m_didSetReferrerPolicy;
ReferrerPolicy m_referrerPolicy;
OwnPtr<MediaListDirective> m_pluginTypes;
OwnPtr<SourceListDirective> m_baseURI;
OwnPtr<SourceListDirective> m_childSrc;
OwnPtr<SourceListDirective> m_connectSrc;
OwnPtr<SourceListDirective> m_defaultSrc;
OwnPtr<SourceListDirective> m_fontSrc;
OwnPtr<SourceListDirective> m_formAction;
OwnPtr<SourceListDirective> m_frameAncestors;
OwnPtr<SourceListDirective> m_frameSrc;
OwnPtr<SourceListDirective> m_imgSrc;
OwnPtr<SourceListDirective> m_mediaSrc;
OwnPtr<SourceListDirective> m_objectSrc;
OwnPtr<SourceListDirective> m_scriptSrc;
OwnPtr<SourceListDirective> m_styleSrc;
Vector<KURL> m_reportURIs;
String m_evalDisabledErrorMessage;
};
} // namespace
#endif
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