| 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
|
|
|