summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/page/csp/ContentSecurityPolicy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/page/csp/ContentSecurityPolicy.cpp')
-rw-r--r--Source/WebCore/page/csp/ContentSecurityPolicy.cpp101
1 files changed, 97 insertions, 4 deletions
diff --git a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp
index 19bf207fa..9e726d5fe 100644
--- a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp
+++ b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp
@@ -29,14 +29,17 @@
#include "ContentSecurityPolicyDirective.h"
#include "ContentSecurityPolicyDirectiveList.h"
+#include "ContentSecurityPolicyHash.h"
#include "ContentSecurityPolicySource.h"
#include "ContentSecurityPolicySourceList.h"
+#include "CryptoDigest.h"
#include "DOMStringList.h"
#include "Document.h"
#include "DocumentLoader.h"
#include "FormData.h"
#include "FormDataList.h"
#include "Frame.h"
+#include "HTMLParserIdioms.h"
#include "InspectorInstrumentation.h"
#include "JSMainThreadExecState.h"
#include "ParsingUtilities.h"
@@ -45,6 +48,7 @@
#include "SchemeRegistry.h"
#include "SecurityOrigin.h"
#include "SecurityPolicyViolationEvent.h"
+#include "TextEncoding.h"
#include <inspector/InspectorValues.h>
#include <inspector/ScriptCallStack.h>
#include <inspector/ScriptCallStackFactory.h>
@@ -193,6 +197,48 @@ bool isAllowedByAllWithContext(const CSPDirectiveListVector& policies, const Str
return true;
}
+template<bool (ContentSecurityPolicyDirectiveList::*allowed)(const String& nonce) const>
+static bool isAllowedByAllWithNonce(const CSPDirectiveListVector& policies, const String& nonce)
+{
+ for (auto& policy : policies) {
+ if (!(policy.get()->*allowed)(nonce))
+ return false;
+ }
+ return true;
+}
+
+static CryptoDigest::Algorithm toCryptoDigestAlgorithm(ContentSecurityPolicyHashAlgorithm algorithm)
+{
+ switch (algorithm) {
+ case ContentSecurityPolicyHashAlgorithm::SHA_256:
+ return CryptoDigest::Algorithm::SHA_256;
+ case ContentSecurityPolicyHashAlgorithm::SHA_384:
+ return CryptoDigest::Algorithm::SHA_384;
+ case ContentSecurityPolicyHashAlgorithm::SHA_512:
+ return CryptoDigest::Algorithm::SHA_512;
+ }
+ ASSERT_NOT_REACHED();
+ return CryptoDigest::Algorithm::SHA_512;
+}
+
+template<bool (ContentSecurityPolicyDirectiveList::*allowed)(const ContentSecurityPolicyHash&) const>
+bool isAllowedByAllWithHashFromContent(const CSPDirectiveListVector& policies, const String& content, const TextEncoding& encoding, OptionSet<ContentSecurityPolicyHashAlgorithm> algorithms)
+{
+ // FIXME: Compute the digest with respect to the raw bytes received from the page.
+ // See <https://bugs.webkit.org/show_bug.cgi?id=155184>.
+ CString contentCString = encoding.encode(content, EntitiesForUnencodables);
+ for (auto algorithm : algorithms) {
+ auto cryptoDigest = CryptoDigest::create(toCryptoDigestAlgorithm(algorithm));
+ cryptoDigest->addBytes(contentCString.data(), contentCString.length());
+ Vector<uint8_t> digest = cryptoDigest->computeHash();
+ for (auto& policy : policies) {
+ if ((policy.get()->*allowed)(std::make_pair(algorithm, digest)))
+ return true;
+ }
+ }
+ return false;
+}
+
template<bool (ContentSecurityPolicyDirectiveList::*allowFromURL)(const URL&, ContentSecurityPolicy::ReportingStatus) const>
bool isAllowedByAllWithURL(const CSPDirectiveListVector& policies, const URL& url, ContentSecurityPolicy::ReportingStatus reportingStatus)
{
@@ -216,14 +262,61 @@ bool ContentSecurityPolicy::allowInlineEventHandlers(const String& contextURL, c
return overrideContentSecurityPolicy || isAllowedByAllWithContext<&ContentSecurityPolicyDirectiveList::allowInlineEventHandlers>(m_policies, contextURL, contextLine, reportingStatus);
}
-bool ContentSecurityPolicy::allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, bool overrideContentSecurityPolicy, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+// FIXME: We should compute the document encoding once and cache it instead of computing it on each invocation.
+const TextEncoding& ContentSecurityPolicy::documentEncoding() const
{
- return overrideContentSecurityPolicy || isAllowedByAllWithContext<&ContentSecurityPolicyDirectiveList::allowInlineScript>(m_policies, contextURL, contextLine, reportingStatus);
+ if (!is<Document>(m_scriptExecutionContext))
+ return UTF8Encoding();
+ Document& document = downcast<Document>(*m_scriptExecutionContext);
+ if (TextResourceDecoder* decoder = document.decoder())
+ return decoder->encoding();
+ return UTF8Encoding();
}
-bool ContentSecurityPolicy::allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, bool overrideContentSecurityPolicy, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+bool ContentSecurityPolicy::allowScriptWithNonce(const String& nonce, bool overrideContentSecurityPolicy) const
{
- return overrideContentSecurityPolicy || m_overrideInlineStyleAllowed || isAllowedByAllWithContext<&ContentSecurityPolicyDirectiveList::allowInlineStyle>(m_policies, contextURL, contextLine, reportingStatus);
+ if (overrideContentSecurityPolicy)
+ return true;
+ String strippedNonce = stripLeadingAndTrailingHTMLSpaces(nonce);
+ if (strippedNonce.isEmpty())
+ return false;
+ if (isAllowedByAllWithNonce<&ContentSecurityPolicyDirectiveList::allowScriptWithNonce>(m_policies, strippedNonce))
+ return true;
+ return false;
+}
+
+bool ContentSecurityPolicy::allowStyleWithNonce(const String& nonce, bool overrideContentSecurityPolicy) const
+{
+ if (overrideContentSecurityPolicy)
+ return true;
+ String strippedNonce = stripLeadingAndTrailingHTMLSpaces(nonce);
+ if (strippedNonce.isEmpty())
+ return false;
+ if (isAllowedByAllWithNonce<&ContentSecurityPolicyDirectiveList::allowStyleWithNonce>(m_policies, strippedNonce))
+ return true;
+ return false;
+}
+
+bool ContentSecurityPolicy::allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, const String& scriptContent, bool overrideContentSecurityPolicy, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ if (overrideContentSecurityPolicy)
+ return true;
+ if (!m_hashAlgorithmsForInlineScripts.isEmpty() && !scriptContent.isEmpty()
+ && isAllowedByAllWithHashFromContent<&ContentSecurityPolicyDirectiveList::allowInlineScriptWithHash>(m_policies, scriptContent, documentEncoding(), m_hashAlgorithmsForInlineScripts))
+ return true;
+ return isAllowedByAllWithContext<&ContentSecurityPolicyDirectiveList::allowInlineScript>(m_policies, contextURL, contextLine, reportingStatus);
+}
+
+bool ContentSecurityPolicy::allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, const String& styleContent, bool overrideContentSecurityPolicy, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+ if (overrideContentSecurityPolicy)
+ return true;
+ if (m_overrideInlineStyleAllowed)
+ return true;
+ if (!m_hashAlgorithmsForInlineStylesheets.isEmpty() && !styleContent.isEmpty()
+ && isAllowedByAllWithHashFromContent<&ContentSecurityPolicyDirectiveList::allowInlineStyleWithHash>(m_policies, styleContent, documentEncoding(), m_hashAlgorithmsForInlineStylesheets))
+ return true;
+ return isAllowedByAllWithContext<&ContentSecurityPolicyDirectiveList::allowInlineStyle>(m_policies, contextURL, contextLine, reportingStatus);
}
bool ContentSecurityPolicy::allowEval(JSC::ExecState* state, bool overrideContentSecurityPolicy, ContentSecurityPolicy::ReportingStatus reportingStatus) const