Chromium Code Reviews| Index: Source/core/frame/ContentSecurityPolicy.cpp |
| diff --git a/Source/core/frame/ContentSecurityPolicy.cpp b/Source/core/frame/ContentSecurityPolicy.cpp |
| index 8caa910fcd7265856a979ef3ca3ef7e600e65167..3e6b30339f1770a917fb998bf970bbcdc99ea05b 100644 |
| --- a/Source/core/frame/ContentSecurityPolicy.cpp |
| +++ b/Source/core/frame/ContentSecurityPolicy.cpp |
| @@ -35,6 +35,7 @@ |
| #include "core/frame/DOMWindow.h" |
| #include "core/frame/LocalFrame.h" |
| #include "core/frame/UseCounter.h" |
| +#include "core/frame/csp/CSPDirectiveList.h" |
| #include "core/frame/csp/CSPSource.h" |
| #include "core/frame/csp/CSPSourceList.h" |
| #include "core/frame/csp/MediaListDirective.h" |
| @@ -65,47 +66,47 @@ |
| namespace WebCore { |
| // CSP 1.0 Directives |
| -static const char connectSrc[] = "connect-src"; |
| -static const char defaultSrc[] = "default-src"; |
| -static const char fontSrc[] = "font-src"; |
| -static const char frameSrc[] = "frame-src"; |
| -static const char imgSrc[] = "img-src"; |
| -static const char mediaSrc[] = "media-src"; |
| -static const char objectSrc[] = "object-src"; |
| -static const char reportURI[] = "report-uri"; |
| -static const char sandbox[] = "sandbox"; |
| -static const char scriptSrc[] = "script-src"; |
| -static const char styleSrc[] = "style-src"; |
| +const char ContentSecurityPolicy::ConnectSrc[] = "connect-src"; |
| +const char ContentSecurityPolicy::DefaultSrc[] = "default-src"; |
| +const char ContentSecurityPolicy::FontSrc[] = "font-src"; |
| +const char ContentSecurityPolicy::FrameSrc[] = "frame-src"; |
| +const char ContentSecurityPolicy::ImgSrc[] = "img-src"; |
| +const char ContentSecurityPolicy::MediaSrc[] = "media-src"; |
| +const char ContentSecurityPolicy::ObjectSrc[] = "object-src"; |
| +const char ContentSecurityPolicy::ReportURI[] = "report-uri"; |
| +const char ContentSecurityPolicy::Sandbox[] = "sandbox"; |
| +const char ContentSecurityPolicy::ScriptSrc[] = "script-src"; |
| +const char ContentSecurityPolicy::StyleSrc[] = "style-src"; |
| // CSP 1.1 Directives |
| -static const char baseURI[] = "base-uri"; |
| -static const char childSrc[] = "child-src"; |
| -static const char formAction[] = "form-action"; |
| -static const char frameAncestors[] = "frame-ancestors"; |
| -static const char pluginTypes[] = "plugin-types"; |
| -static const char reflectedXSS[] = "reflected-xss"; |
| -static const char referrer[] = "referrer"; |
| +const char ContentSecurityPolicy::BaseURI[] = "base-uri"; |
| +const char ContentSecurityPolicy::ChildSrc[] = "child-src"; |
| +const char ContentSecurityPolicy::FormAction[] = "form-action"; |
| +const char ContentSecurityPolicy::FrameAncestors[] = "frame-ancestors"; |
| +const char ContentSecurityPolicy::PluginTypes[] = "plugin-types"; |
| +const char ContentSecurityPolicy::ReflectedXSS[] = "reflected-xss"; |
| +const char ContentSecurityPolicy::Referrer[] = "referrer"; |
| bool ContentSecurityPolicy::isDirectiveName(const String& name) |
| { |
| - return (equalIgnoringCase(name, connectSrc) |
| - || equalIgnoringCase(name, defaultSrc) |
| - || equalIgnoringCase(name, fontSrc) |
| - || equalIgnoringCase(name, frameSrc) |
| - || equalIgnoringCase(name, imgSrc) |
| - || equalIgnoringCase(name, mediaSrc) |
| - || equalIgnoringCase(name, objectSrc) |
| - || equalIgnoringCase(name, reportURI) |
| - || equalIgnoringCase(name, sandbox) |
| - || equalIgnoringCase(name, scriptSrc) |
| - || equalIgnoringCase(name, styleSrc) |
| - || equalIgnoringCase(name, baseURI) |
| - || equalIgnoringCase(name, childSrc) |
| - || equalIgnoringCase(name, formAction) |
| - || equalIgnoringCase(name, frameAncestors) |
| - || equalIgnoringCase(name, pluginTypes) |
| - || equalIgnoringCase(name, reflectedXSS) |
| - || equalIgnoringCase(name, referrer) |
| + return (equalIgnoringCase(name, ConnectSrc) |
| + || equalIgnoringCase(name, DefaultSrc) |
|
kenneth.r.christiansen
2014/03/04 10:45:24
We are getting quite many here... :-) I was wonder
|
| + || equalIgnoringCase(name, FontSrc) |
| + || equalIgnoringCase(name, FrameSrc) |
| + || equalIgnoringCase(name, ImgSrc) |
| + || equalIgnoringCase(name, MediaSrc) |
| + || equalIgnoringCase(name, ObjectSrc) |
| + || equalIgnoringCase(name, ReportURI) |
| + || equalIgnoringCase(name, Sandbox) |
| + || equalIgnoringCase(name, ScriptSrc) |
| + || equalIgnoringCase(name, StyleSrc) |
| + || equalIgnoringCase(name, BaseURI) |
| + || equalIgnoringCase(name, ChildSrc) |
| + || equalIgnoringCase(name, FormAction) |
| + || equalIgnoringCase(name, FrameAncestors) |
| + || equalIgnoringCase(name, PluginTypes) |
| + || equalIgnoringCase(name, ReflectedXSS) |
| + || equalIgnoringCase(name, Referrer) |
| ); |
| } |
| @@ -128,782 +129,6 @@ static ReferrerPolicy mergeReferrerPolicies(ReferrerPolicy a, ReferrerPolicy b) |
| 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) |
| : m_client(client) |
| , m_overrideInlineStyleAllowed(false) |