Index: third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicyTest.cpp |
diff --git a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicyTest.cpp b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicyTest.cpp |
index 2226c071005a02242fb7b70eba7f28ed91f7c629..21a4aa270bc72260d78ae8fe64298f24e2dfa822 100644 |
--- a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicyTest.cpp |
+++ b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicyTest.cpp |
@@ -7,6 +7,7 @@ |
#include "core/dom/Document.h" |
#include "core/frame/csp/CSPDirectiveList.h" |
#include "core/loader/DocumentLoader.h" |
+#include "core/testing/DummyPageHolder.h" |
#include "platform/RuntimeEnabledFeatures.h" |
#include "platform/network/ContentSecurityPolicyParsers.h" |
#include "platform/network/ResourceRequest.h" |
@@ -91,7 +92,7 @@ TEST_F(ContentSecurityPolicyTest, CopyStateFrom) |
ContentSecurityPolicy* csp2 = ContentSecurityPolicy::create(); |
csp2->copyStateFrom(csp.get()); |
- EXPECT_FALSE(csp2->allowScriptFromSource(exampleUrl, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport)); |
+ EXPECT_FALSE(csp2->allowScriptFromSource(exampleUrl, String(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport)); |
EXPECT_TRUE(csp2->allowPluginType("application/x-type-1", "application/x-type-1", exampleUrl, ContentSecurityPolicy::SuppressReport)); |
EXPECT_TRUE(csp2->allowImageFromSource(exampleUrl, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport)); |
EXPECT_FALSE(csp2->allowImageFromSource(notExampleUrl, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport)); |
@@ -108,7 +109,7 @@ TEST_F(ContentSecurityPolicyTest, CopyPluginTypesFrom) |
ContentSecurityPolicy* csp2 = ContentSecurityPolicy::create(); |
csp2->copyPluginTypesFrom(csp.get()); |
- EXPECT_TRUE(csp2->allowScriptFromSource(exampleUrl, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport)); |
+ EXPECT_TRUE(csp2->allowScriptFromSource(exampleUrl, String(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport)); |
EXPECT_TRUE(csp2->allowPluginType("application/x-type-1", "application/x-type-1", exampleUrl, ContentSecurityPolicy::SuppressReport)); |
EXPECT_TRUE(csp2->allowImageFromSource(exampleUrl, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport)); |
EXPECT_TRUE(csp2->allowImageFromSource(notExampleUrl, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport)); |
@@ -205,9 +206,174 @@ TEST_F(ContentSecurityPolicyTest, ObjectSrc) |
KURL url(KURL(), "https://example.test"); |
csp->bindToExecutionContext(document.get()); |
csp->didReceiveHeader("object-src 'none';", ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceMeta); |
- EXPECT_FALSE(csp->allowRequest(WebURLRequest::RequestContextObject, url, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport)); |
- EXPECT_FALSE(csp->allowRequest(WebURLRequest::RequestContextEmbed, url, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport)); |
- EXPECT_TRUE(csp->allowRequest(WebURLRequest::RequestContextPlugin, url, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport)); |
+ EXPECT_FALSE(csp->allowRequest(WebURLRequest::RequestContextObject, url, String(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport)); |
+ EXPECT_FALSE(csp->allowRequest(WebURLRequest::RequestContextEmbed, url, String(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport)); |
+ EXPECT_TRUE(csp->allowRequest(WebURLRequest::RequestContextPlugin, url, String(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport)); |
+} |
+ |
+TEST_F(ContentSecurityPolicyTest, NonceSinglePolicy) |
+{ |
+ struct TestCase { |
+ const char* policy; |
+ const char* url; |
+ const char* nonce; |
+ bool allowed; |
+ } cases[] = { |
+ { "script-src 'nonce-yay'", "https://example.com/js", "", false }, |
+ { "script-src 'nonce-yay'", "https://example.com/js", "yay", true }, |
+ { "script-src https://example.com", "https://example.com/js", "", true }, |
+ { "script-src https://example.com", "https://example.com/js", "yay", true }, |
+ { "script-src https://example.com 'nonce-yay'", "https://not.example.com/js", "", false }, |
+ { "script-src https://example.com 'nonce-yay'", "https://not.example.com/js", "yay", true }, |
+ }; |
+ |
+ for (const auto& test : cases) { |
+ SCOPED_TRACE(testing::Message() << "Policy: `" << test.policy << "`, URL: `" << test.url << "`, Nonce: `" << test.nonce << "`"); |
+ KURL resource = KURL(KURL(), test.url); |
+ |
+ unsigned expectedReports = test.allowed ? 0u : 1u; |
+ |
+ // Single enforce-mode policy should match `test.expected`: |
+ Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::create(); |
+ policy->bindToExecutionContext(document.get()); |
+ policy->didReceiveHeader(test.policy, ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceHTTP); |
+ EXPECT_EQ(test.allowed, policy->allowScriptFromSource(resource, String(test.nonce))); |
+ // If this is expected to generate a violation, we should have sent a report. |
+ EXPECT_EQ(expectedReports, policy->m_violationReportsSent.size()); |
+ |
+ // Single report-mode policy should always be `true`: |
+ policy = ContentSecurityPolicy::create(); |
+ policy->bindToExecutionContext(document.get()); |
+ policy->didReceiveHeader(test.policy, ContentSecurityPolicyHeaderTypeReport, ContentSecurityPolicyHeaderSourceHTTP); |
+ EXPECT_TRUE(policy->allowScriptFromSource(resource, String(test.nonce))); |
+ // If this is expected to generate a violation, we should have sent a report, even though |
+ // we don't deny access in `allowScriptFromSource`: |
+ EXPECT_EQ(expectedReports, policy->m_violationReportsSent.size()); |
+ } |
+} |
+ |
+TEST_F(ContentSecurityPolicyTest, NonceInline) |
+{ |
+ struct TestCase { |
+ const char* policy; |
+ const char* nonce; |
+ bool allowed; |
+ } cases[] = { |
+ { "'unsafe-inline'", "", true }, |
+ { "'unsafe-inline'", "yay", true }, |
+ { "'nonce-yay'", "", false }, |
+ { "'nonce-yay'", "yay", true }, |
+ { "'unsafe-inline' 'nonce-yay'", "", false }, |
+ { "'unsafe-inline' 'nonce-yay'", "yay", true }, |
+ }; |
+ |
+ String contextURL; |
+ String content; |
+ WTF::OrdinalNumber contextLine; |
+ for (const auto& test : cases) { |
+ SCOPED_TRACE(testing::Message() << "Policy: `" << test.policy << "`, Nonce: `" << test.nonce << "`"); |
+ |
+ unsigned expectedReports = test.allowed ? 0u : 1u; |
+ |
+ // Enforce 'script-src' |
+ Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::create(); |
+ policy->bindToExecutionContext(document.get()); |
+ policy->didReceiveHeader(String("script-src ") + test.policy, ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceHTTP); |
+ EXPECT_EQ(test.allowed, policy->allowInlineScript(contextURL, String(test.nonce), contextLine, content)); |
+ EXPECT_EQ(expectedReports, policy->m_violationReportsSent.size()); |
+ |
+ // Enforce 'style-src' |
+ policy = ContentSecurityPolicy::create(); |
+ policy->bindToExecutionContext(document.get()); |
+ policy->didReceiveHeader(String("style-src ") + test.policy, ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceHTTP); |
+ EXPECT_EQ(test.allowed, policy->allowInlineStyle(contextURL, String(test.nonce), contextLine, content)); |
+ EXPECT_EQ(expectedReports, policy->m_violationReportsSent.size()); |
+ |
+ // Report 'script-src' |
+ policy = ContentSecurityPolicy::create(); |
+ policy->bindToExecutionContext(document.get()); |
+ policy->didReceiveHeader(String("script-src ") + test.policy, ContentSecurityPolicyHeaderTypeReport, ContentSecurityPolicyHeaderSourceHTTP); |
+ EXPECT_TRUE(policy->allowInlineScript(contextURL, String(test.nonce), contextLine, content)); |
+ EXPECT_EQ(expectedReports, policy->m_violationReportsSent.size()); |
+ |
+ // Report 'style-src' |
+ policy = ContentSecurityPolicy::create(); |
+ policy->bindToExecutionContext(document.get()); |
+ policy->didReceiveHeader(String("style-src ") + test.policy, ContentSecurityPolicyHeaderTypeReport, ContentSecurityPolicyHeaderSourceHTTP); |
+ EXPECT_TRUE(policy->allowInlineStyle(contextURL, String(test.nonce), contextLine, content)); |
+ EXPECT_EQ(expectedReports, policy->m_violationReportsSent.size()); |
+ } |
+} |
+ |
+TEST_F(ContentSecurityPolicyTest, NonceMultiplePolicy) |
+{ |
+ struct TestCase { |
+ const char* policy1; |
+ const char* policy2; |
+ const char* url; |
+ const char* nonce; |
+ bool allowed1; |
+ bool allowed2; |
+ } cases[] = { |
+ // Passes both: |
+ { "script-src 'nonce-yay'", "script-src 'nonce-yay'", "https://example.com/js", "yay", true, true }, |
+ { "script-src https://example.com", "script-src 'nonce-yay'", "https://example.com/js", "yay", true, true }, |
+ { "script-src 'nonce-yay'", "script-src https://example.com", "https://example.com/js", "yay", true, true }, |
+ { "script-src https://example.com 'nonce-yay'", "script-src https://example.com 'nonce-yay'", "https://example.com/js", "yay", true, true }, |
+ { "script-src https://example.com 'nonce-yay'", "script-src https://example.com 'nonce-yay'", "https://example.com/js", "", true, true }, |
+ { "script-src https://example.com", "script-src https://example.com 'nonce-yay'", "https://example.com/js", "yay", true, true }, |
+ { "script-src https://example.com 'nonce-yay'", "script-src https://example.com", "https://example.com/js", "yay", true, true }, |
+ |
+ // Fails one: |
+ { "script-src 'nonce-yay'", "script-src https://example.com", "https://example.com/js", "", false, true }, |
+ { "script-src 'nonce-yay'", "script-src 'none'", "https://example.com/js", "yay", true, false }, |
+ { "script-src 'nonce-yay'", "script-src https://not.example.com", "https://example.com/js", "yay", true, false }, |
+ |
+ // Fails both: |
+ { "script-src 'nonce-yay'", "script-src https://example.com", "https://not.example.com/js", "", false, false }, |
+ { "script-src https://example.com", "script-src 'nonce-yay'", "https://not.example.com/js", "", false, false }, |
+ { "script-src 'nonce-yay'", "script-src 'none'", "https://not.example.com/js", "boo", false, false }, |
+ { "script-src 'nonce-yay'", "script-src https://not.example.com", "https://example.com/js", "", false, false }, |
+ }; |
+ |
+ for (const auto& test : cases) { |
+ SCOPED_TRACE(testing::Message() << "Policy: `" << test.policy1 << "`/`" << test.policy2 << "`, URL: `" << test.url << "`, Nonce: `" << test.nonce << "`"); |
+ KURL resource = KURL(KURL(), test.url); |
+ |
+ unsigned expectedReports = test.allowed1 != test.allowed2 ? 1u : (test.allowed1 ? 0u : 2u); |
+ |
+ // Enforce / Report |
+ Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::create(); |
+ policy->bindToExecutionContext(document.get()); |
+ policy->didReceiveHeader(test.policy1, ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceHTTP); |
+ policy->didReceiveHeader(test.policy2, ContentSecurityPolicyHeaderTypeReport, ContentSecurityPolicyHeaderSourceHTTP); |
+ EXPECT_EQ(test.allowed1, policy->allowScriptFromSource(resource, String(test.nonce))); |
+ EXPECT_EQ(expectedReports, policy->m_violationReportsSent.size()); |
+ |
+ // Report / Enforce |
+ policy = ContentSecurityPolicy::create(); |
+ policy->bindToExecutionContext(document.get()); |
+ policy->didReceiveHeader(test.policy1, ContentSecurityPolicyHeaderTypeReport, ContentSecurityPolicyHeaderSourceHTTP); |
+ policy->didReceiveHeader(test.policy2, ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceHTTP); |
+ EXPECT_EQ(test.allowed2, policy->allowScriptFromSource(resource, String(test.nonce))); |
+ EXPECT_EQ(expectedReports, policy->m_violationReportsSent.size()); |
+ |
+ // Enforce / Enforce |
+ policy = ContentSecurityPolicy::create(); |
+ policy->bindToExecutionContext(document.get()); |
+ policy->didReceiveHeader(test.policy1, ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceHTTP); |
+ policy->didReceiveHeader(test.policy2, ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceHTTP); |
+ EXPECT_EQ(test.allowed1 && test.allowed2, policy->allowScriptFromSource(resource, String(test.nonce))); |
+ EXPECT_EQ(expectedReports, policy->m_violationReportsSent.size()); |
+ |
+ // Report / Report |
+ policy = ContentSecurityPolicy::create(); |
+ policy->bindToExecutionContext(document.get()); |
+ policy->didReceiveHeader(test.policy1, ContentSecurityPolicyHeaderTypeReport, ContentSecurityPolicyHeaderSourceHTTP); |
+ policy->didReceiveHeader(test.policy2, ContentSecurityPolicyHeaderTypeReport, ContentSecurityPolicyHeaderSourceHTTP); |
+ EXPECT_TRUE(policy->allowScriptFromSource(resource, String(test.nonce))); |
+ EXPECT_EQ(expectedReports, policy->m_violationReportsSent.size()); |
+ } |
} |
} // namespace blink |