Index: Source/core/frame/ContentSecurityPolicy.cpp |
diff --git a/Source/core/frame/ContentSecurityPolicy.cpp b/Source/core/frame/ContentSecurityPolicy.cpp |
index e4b9eb18c21379dec8d909be260a627ac9d22e7e..dbcd2d3d318896d52ed07ba3d47d5d75506f6faf 100644 |
--- a/Source/core/frame/ContentSecurityPolicy.cpp |
+++ b/Source/core/frame/ContentSecurityPolicy.cpp |
@@ -149,6 +149,7 @@ static const char styleSrc[] = "style-src"; |
// CSP 1.1 Directives |
static const char baseURI[] = "base-uri"; |
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"; |
@@ -168,6 +169,7 @@ bool isDirectiveName(const String& name) |
|| equalIgnoringCase(name, styleSrc) |
|| equalIgnoringCase(name, baseURI) |
|| equalIgnoringCase(name, formAction) |
+ || equalIgnoringCase(name, frameAncestors) |
|| equalIgnoringCase(name, pluginTypes) |
|| equalIgnoringCase(name, reflectedXSS) |
|| equalIgnoringCase(name, referrer) |
@@ -893,6 +895,7 @@ public: |
bool allowConnectToSource(const KURL&, ContentSecurityPolicy::ReportingStatus) const; |
bool allowFormAction(const KURL&, ContentSecurityPolicy::ReportingStatus) const; |
bool allowBaseURI(const KURL&, ContentSecurityPolicy::ReportingStatus) const; |
+ bool allowAncestors(Frame*, ContentSecurityPolicy::ReportingStatus) const; |
bool allowScriptNonce(const String&) const; |
bool allowStyleNonce(const String&) const; |
bool allowScriptHash(const SourceHashValue&) const; |
@@ -930,6 +933,7 @@ private: |
bool checkHash(SourceListDirective*, const SourceHashValue&) const; |
bool checkSource(SourceListDirective*, const KURL&) const; |
bool checkMediaType(MediaListDirective*, const String& type, const String& typeAttribute) const; |
+ bool checkAncestors(SourceListDirective*, Frame*) const; |
void setEvalDisabledErrorMessage(const String& errorMessage) { m_evalDisabledErrorMessage = errorMessage; } |
@@ -938,6 +942,7 @@ private: |
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*, Frame*) const; |
bool denyIfEnforcingPolicy() const { return m_reportOnly; } |
@@ -960,6 +965,7 @@ private: |
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; |
@@ -1047,6 +1053,18 @@ bool CSPDirectiveList::checkSource(SourceListDirective* directive, const KURL& u |
return !directive || directive->allows(url); |
} |
+bool CSPDirectiveList::checkAncestors(SourceListDirective* directive, Frame* frame) const |
+{ |
+ if (!frame || !directive) |
+ return true; |
+ |
+ for (Frame* 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) |
@@ -1151,6 +1169,15 @@ bool CSPDirectiveList::checkSourceAndReportViolation(SourceListDirective* direct |
return denyIfEnforcingPolicy(); |
} |
+bool CSPDirectiveList::checkAncestorsAndReportViolation(SourceListDirective* directive, Frame* 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: ")); |
@@ -1274,6 +1301,13 @@ bool CSPDirectiveList::allowBaseURI(const KURL& url, ContentSecurityPolicy::Repo |
checkSource(m_baseURI.get(), url); |
} |
+bool CSPDirectiveList::allowAncestors(Frame* frame, ContentSecurityPolicy::ReportingStatus reportingStatus) const |
+{ |
+ return reportingStatus == ContentSecurityPolicy::SendReport ? |
+ checkAncestorsAndReportViolation(m_frameAncestors.get(), frame) : |
+ checkAncestors(m_frameAncestors.get(), frame); |
+} |
+ |
bool CSPDirectiveList::allowScriptNonce(const String& nonce) const |
{ |
return checkNonce(operativeDirective(m_scriptSrc.get()), nonce); |
@@ -1563,6 +1597,8 @@ void CSPDirectiveList::addDirective(const String& name, const String& value) |
setCSPDirective<SourceListDirective>(name, value, m_baseURI); |
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)) |
@@ -1746,6 +1782,16 @@ bool isAllowedByAllWithURL(const CSPDirectiveListVector& policies, const KURL& u |
return true; |
} |
+template<bool (CSPDirectiveList::*allowed)(Frame*, ContentSecurityPolicy::ReportingStatus) const> |
+bool isAllowedByAllWithFrame(const CSPDirectiveListVector& policies, Frame* frame, ContentSecurityPolicy::ReportingStatus reportingStatus) |
+{ |
+ for (size_t i = 0; i < policies.size(); ++i) { |
+ if (!(policies[i].get()->*allowed)(frame, reportingStatus)) |
+ return false; |
+ } |
+ return true; |
+} |
+ |
bool ContentSecurityPolicy::allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, ContentSecurityPolicy::ReportingStatus reportingStatus) const |
{ |
return isAllowedByAllWithContext<&CSPDirectiveList::allowJavaScriptURLs>(m_policies, contextURL, contextLine, reportingStatus); |
@@ -1894,6 +1940,11 @@ bool ContentSecurityPolicy::allowBaseURI(const KURL& url, ContentSecurityPolicy: |
return isAllowedByAllWithURL<&CSPDirectiveList::allowBaseURI>(m_policies, url, reportingStatus); |
} |
+bool ContentSecurityPolicy::allowAncestors(Frame* frame, ContentSecurityPolicy::ReportingStatus reportingStatus) const |
+{ |
+ return isAllowedByAllWithFrame<&CSPDirectiveList::allowAncestors>(m_policies, frame, reportingStatus); |
+} |
+ |
bool ContentSecurityPolicy::isActive() const |
{ |
return !m_policies.isEmpty(); |