| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "third_party/blink/renderer/core/frame/csp/source_list_directive.h" |
| |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h" |
| #include "third_party/blink/renderer/core/frame/csp/csp_source.h" |
| #include "third_party/blink/renderer/core/testing/null_execution_context.h" |
| #include "third_party/blink/renderer/platform/heap/heap.h" |
| #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h" |
| #include "third_party/blink/renderer/platform/weborigin/kurl.h" |
| #include "third_party/blink/renderer/platform/weborigin/security_origin.h" |
| |
| namespace blink { |
| |
| class SourceListDirectiveTest : public testing::Test { |
| public: |
| SourceListDirectiveTest() |
| : csp(MakeGarbageCollected<ContentSecurityPolicy>()) {} |
| ~SourceListDirectiveTest() override { context->NotifyContextDestroyed(); } |
| |
| protected: |
| struct Source { |
| String scheme; |
| String host; |
| const int port; |
| String path; |
| bool host_wildcard; |
| bool port_wildcard; |
| }; |
| |
| void SetUp() override { |
| KURL secure_url("https://example.test/image.png"); |
| self_source = network::mojom::blink::CSPSource::New("https", "example.test", |
| 443, "", false, false); |
| context = MakeGarbageCollected<NullExecutionContext>(); |
| context->GetSecurityContext().SetSecurityOrigin( |
| SecurityOrigin::Create(secure_url)); |
| csp->BindToDelegate(context->GetContentSecurityPolicyDelegate()); |
| } |
| |
| Persistent<ContentSecurityPolicy> csp; |
| Persistent<ExecutionContext> context; |
| network::mojom::blink::CSPSourcePtr self_source; |
| }; |
| |
| TEST_F(SourceListDirectiveTest, BasicMatchingNone) { |
| KURL base; |
| String sources = "'none'"; |
| network::mojom::blink::CSPSourceListPtr source_list = |
| CSPSourceListParse("script-src", sources, csp.Get()); |
| ASSERT_TRUE(source_list); |
| |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://example.com/"))); |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "https://example.test/"))); |
| } |
| |
| TEST_F(SourceListDirectiveTest, BasicMatchingStrictDynamic) { |
| String sources = "'strict-dynamic'"; |
| network::mojom::blink::CSPSourceListPtr source_list = |
| CSPSourceListParse("script-src", sources, csp.Get()); |
| |
| EXPECT_TRUE(source_list->allow_dynamic); |
| } |
| |
| TEST_F(SourceListDirectiveTest, BasicMatchingUnsafeHashes) { |
| String sources = "'unsafe-hashes'"; |
| network::mojom::blink::CSPSourceListPtr source_list = |
| CSPSourceListParse("script-src", sources, csp.Get()); |
| |
| EXPECT_TRUE(source_list->allow_unsafe_hashes); |
| } |
| |
| TEST_F(SourceListDirectiveTest, BasicMatchingStar) { |
| KURL base; |
| String sources = "*"; |
| network::mojom::blink::CSPSourceListPtr source_list = |
| CSPSourceListParse("script-src", sources, csp.Get()); |
| |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://example.com/"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "https://example.com/"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://example.com/bar"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://foo.example.com/"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://foo.example.com/bar"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "ftp://example.com/"))); |
| |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "data:https://example.test/"))); |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "blob:https://example.test/"))); |
| EXPECT_FALSE( |
| CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "filesystem:https://example.test/"))); |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "file:///etc/hosts"))); |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "applewebdata://example.test/"))); |
| } |
| |
| TEST_F(SourceListDirectiveTest, StarallowsSelf) { |
| KURL base; |
| String sources = "*"; |
| network::mojom::blink::CSPSourceListPtr source_list = |
| CSPSourceListParse("script-src", sources, csp.Get()); |
| |
| auto self_origin = |
| network::mojom::blink::CSPSource::New("file", "", -1, "", false, false); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_origin, |
| KURL(base, "file:///etc/hosts"))); |
| |
| // The other results are the same as above: |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_origin, |
| KURL(base, "http://example.com/"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_origin, |
| KURL(base, "https://example.com/"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_origin, |
| KURL(base, "http://example.com/bar"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_origin, |
| KURL(base, "http://foo.example.com/"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_origin, |
| KURL(base, "http://foo.example.com/bar"))); |
| |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_origin, |
| KURL(base, "data:https://example.test/"))); |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_origin, |
| KURL(base, "blob:https://example.test/"))); |
| EXPECT_FALSE( |
| CSPSourceListAllows(*source_list, *self_origin, |
| KURL(base, "filesystem:https://example.test/"))); |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_origin, |
| KURL(base, "applewebdata://example.test/"))); |
| } |
| |
| TEST_F(SourceListDirectiveTest, BasicMatchingSelf) { |
| KURL base; |
| String sources = "'self'"; |
| network::mojom::blink::CSPSourceListPtr source_list = |
| CSPSourceListParse("script-src", sources, csp.Get()); |
| |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://example.com/"))); |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "https://not-example.com/"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "https://example.test/"))); |
| } |
| |
| TEST_F(SourceListDirectiveTest, BlobMatchingBlob) { |
| KURL base; |
| String sources = "blob:"; |
| network::mojom::blink::CSPSourceListPtr source_list = |
| CSPSourceListParse("script-src", sources, csp.Get()); |
| |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "https://example.test/"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "blob:https://example.test/"))); |
| } |
| |
| TEST_F(SourceListDirectiveTest, BasicMatching) { |
| KURL base; |
| String sources = "http://example1.com:8000/foo/ https://example2.com/"; |
| network::mojom::blink::CSPSourceListPtr source_list = |
| CSPSourceListParse("script-src", sources, csp.Get()); |
| |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://example1.com:8000/foo/"))); |
| EXPECT_TRUE( |
| CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://example1.com:8000/foo/bar"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "https://example2.com/"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "https://example2.com/foo/"))); |
| |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "https://not-example.com/"))); |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://example1.com/"))); |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "https://example1.com/foo"))); |
| EXPECT_FALSE(CSPSourceListAllows( |
| *source_list, *self_source, KURL(base, "http://example1.com:9000/foo/"))); |
| EXPECT_FALSE(CSPSourceListAllows( |
| *source_list, *self_source, KURL(base, "http://example1.com:8000/FOO/"))); |
| } |
| |
| TEST_F(SourceListDirectiveTest, WildcardMatching) { |
| KURL base; |
| String sources = |
| "http://example1.com:*/foo/ https://*.example2.com/bar/ http://*.test/"; |
| network::mojom::blink::CSPSourceListPtr source_list = |
| CSPSourceListParse("script-src", sources, csp.Get()); |
| |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://example1.com/foo/"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://example1.com:8000/foo/"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://example1.com:9000/foo/"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "https://foo.example2.com/bar/"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://foo.test/"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://foo.bar.test/"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "https://example1.com/foo/"))); |
| EXPECT_TRUE( |
| CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "https://example1.com:8000/foo/"))); |
| EXPECT_TRUE( |
| CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "https://example1.com:9000/foo/"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "https://foo.test/"))); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "https://foo.bar.test/"))); |
| |
| EXPECT_FALSE(CSPSourceListAllows( |
| *source_list, *self_source, KURL(base, "https://example1.com:8000/foo"))); |
| EXPECT_FALSE(CSPSourceListAllows( |
| *source_list, *self_source, KURL(base, "https://example2.com:8000/bar"))); |
| EXPECT_FALSE( |
| CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "https://foo.example2.com:8000/bar"))); |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "https://example2.foo.com/bar"))); |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://foo.test.bar/"))); |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "https://example2.com/bar/"))); |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://test/"))); |
| } |
| |
| TEST_F(SourceListDirectiveTest, RedirectMatching) { |
| KURL base; |
| String sources = "http://example1.com/foo/ http://example2.com/bar/"; |
| network::mojom::blink::CSPSourceListPtr source_list = |
| CSPSourceListParse("script-src", sources, csp.Get()); |
| |
| EXPECT_TRUE(CSPSourceListAllows( |
| *source_list, *self_source, KURL(base, "http://example1.com/foo/"), |
| ResourceRequest::RedirectStatus::kFollowedRedirect)); |
| EXPECT_TRUE(CSPSourceListAllows( |
| *source_list, *self_source, KURL(base, "http://example1.com/bar/"), |
| ResourceRequest::RedirectStatus::kFollowedRedirect)); |
| EXPECT_TRUE(CSPSourceListAllows( |
| *source_list, *self_source, KURL(base, "http://example2.com/bar/"), |
| ResourceRequest::RedirectStatus::kFollowedRedirect)); |
| EXPECT_TRUE(CSPSourceListAllows( |
| *source_list, *self_source, KURL(base, "http://example2.com/foo/"), |
| ResourceRequest::RedirectStatus::kFollowedRedirect)); |
| EXPECT_TRUE(CSPSourceListAllows( |
| *source_list, *self_source, KURL(base, "https://example1.com/foo/"), |
| ResourceRequest::RedirectStatus::kFollowedRedirect)); |
| EXPECT_TRUE(CSPSourceListAllows( |
| *source_list, *self_source, KURL(base, "https://example1.com/bar/"), |
| ResourceRequest::RedirectStatus::kFollowedRedirect)); |
| |
| EXPECT_FALSE(CSPSourceListAllows( |
| *source_list, *self_source, KURL(base, "http://example3.com/foo/"), |
| ResourceRequest::RedirectStatus::kFollowedRedirect)); |
| } |
| |
| TEST_F(SourceListDirectiveTest, AllowAllInline) { |
| struct TestCase { |
| String sources; |
| bool expected; |
| } cases[] = { |
| // List does not contain 'unsafe-inline'. |
| {"http://example1.com/foo/", false}, |
| {"'sha512-321cba'", false}, |
| {"'nonce-yay'", false}, |
| {"'strict-dynamic'", false}, |
| {"'sha512-321cba' http://example1.com/foo/", false}, |
| {"http://example1.com/foo/ 'sha512-321cba'", false}, |
| {"http://example1.com/foo/ 'nonce-yay'", false}, |
| {"'sha512-321cba' 'nonce-yay'", false}, |
| {"http://example1.com/foo/ 'sha512-321cba' 'nonce-yay'", false}, |
| {"http://example1.com/foo/ 'sha512-321cba' 'nonce-yay'", false}, |
| {" 'sha512-321cba' 'nonce-yay' 'strict-dynamic'", false}, |
| // List contains 'unsafe-inline'. |
| {"'unsafe-inline'", true}, |
| {"'self' 'unsafe-inline'", true}, |
| {"'unsafe-inline' http://example1.com/foo/", true}, |
| {"'sha512-321cba' 'unsafe-inline'", false}, |
| {"'nonce-yay' 'unsafe-inline'", false}, |
| {"'strict-dynamic' 'unsafe-inline' 'nonce-yay'", false}, |
| {"'sha512-321cba' http://example1.com/foo/ 'unsafe-inline'", false}, |
| {"http://example1.com/foo/ 'sha512-321cba' 'unsafe-inline'", false}, |
| {"http://example1.com/foo/ 'nonce-yay' 'unsafe-inline'", false}, |
| {"'sha512-321cba' 'nonce-yay' 'unsafe-inline'", false}, |
| {"http://example1.com/foo/ 'sha512-321cba' 'unsafe-inline' 'nonce-yay'", |
| false}, |
| {"http://example1.com/foo/ 'sha512-321cba' 'nonce-yay' 'unsafe-inline'", |
| false}, |
| {" 'sha512-321cba' 'unsafe-inline' 'nonce-yay' 'strict-dynamic'", false}, |
| }; |
| |
| // Script-src and style-src differently handle presence of 'strict-dynamic'. |
| network::mojom::blink::CSPSourceListPtr script_src = CSPSourceListParse( |
| "script-src", "'strict-dynamic' 'unsafe-inline'", csp.Get()); |
| EXPECT_FALSE( |
| CSPSourceListAllowAllInline(CSPDirectiveName::ScriptSrc, *script_src)); |
| |
| network::mojom::blink::CSPSourceListPtr style_src = CSPSourceListParse( |
| "style-src", "'strict-dynamic' 'unsafe-inline'", csp.Get()); |
| EXPECT_TRUE( |
| CSPSourceListAllowAllInline(CSPDirectiveName::StyleSrc, *style_src)); |
| |
| for (const auto& test : cases) { |
| network::mojom::blink::CSPSourceListPtr script_src = |
| CSPSourceListParse("script-src", test.sources, csp.Get()); |
| EXPECT_EQ( |
| CSPSourceListAllowAllInline(CSPDirectiveName::ScriptSrc, *script_src), |
| test.expected); |
| |
| network::mojom::blink::CSPSourceListPtr style_src = |
| CSPSourceListParse("style-src", test.sources, csp.Get()); |
| EXPECT_EQ( |
| CSPSourceListAllowAllInline(CSPDirectiveName::StyleSrc, *style_src), |
| test.expected); |
| |
| // If source list doesn't have a valid type, it must not allow all inline. |
| network::mojom::blink::CSPSourceListPtr img_src = |
| CSPSourceListParse("img-src", test.sources, csp.Get()); |
| EXPECT_FALSE( |
| CSPSourceListAllowAllInline(CSPDirectiveName::ImgSrc, *img_src)); |
| } |
| } |
| |
| TEST_F(SourceListDirectiveTest, IsNone) { |
| struct TestCase { |
| String sources; |
| bool expected; |
| } cases[] = { |
| // Source list is 'none'. |
| {"'none'", true}, |
| {"", true}, |
| {" ", true}, |
| // Source list is not 'none'. |
| {"http://example1.com/foo/", false}, |
| {"'sha512-321cba'", false}, |
| {"'nonce-yay'", false}, |
| {"'strict-dynamic'", false}, |
| {"'sha512-321cba' http://example1.com/foo/", false}, |
| {"http://example1.com/foo/ 'sha512-321cba'", false}, |
| {"http://example1.com/foo/ 'nonce-yay'", false}, |
| {"'none' 'sha512-321cba' http://example1.com/foo/", false}, |
| {"'none' http://example1.com/foo/ 'sha512-321cba'", false}, |
| {"'none' http://example1.com/foo/ 'nonce-yay'", false}, |
| {"'sha512-321cba' 'nonce-yay'", false}, |
| {"http://example1.com/foo/ 'sha512-321cba' 'nonce-yay'", false}, |
| {"http://example1.com/foo/ 'sha512-321cba' 'nonce-yay'", false}, |
| {" 'sha512-321cba' 'nonce-yay' 'strict-dynamic'", false}, |
| }; |
| |
| for (const auto& test : cases) { |
| SCOPED_TRACE(test.sources); |
| network::mojom::blink::CSPSourceListPtr script_src = |
| CSPSourceListParse("script-src", test.sources, csp.Get()); |
| EXPECT_EQ(CSPSourceListIsNone(*script_src), test.expected); |
| |
| network::mojom::blink::CSPSourceListPtr form_action = |
| CSPSourceListParse("form-action", test.sources, csp.Get()); |
| EXPECT_EQ(CSPSourceListIsNone(*form_action), test.expected); |
| |
| network::mojom::blink::CSPSourceListPtr frame_src = |
| CSPSourceListParse("frame-src", test.sources, csp.Get()); |
| EXPECT_EQ(CSPSourceListIsNone(*frame_src), test.expected); |
| } |
| } |
| |
| TEST_F(SourceListDirectiveTest, IsSelf) { |
| struct TestCase { |
| String sources; |
| bool expected; |
| } cases[] = { |
| // Source list is 'self'. |
| {"'self'", true}, |
| {"'self' 'none'", true}, |
| |
| // Source list is not 'self'. |
| {"'none'", false}, |
| {"http://example1.com/foo/", false}, |
| {"'sha512-321cba'", false}, |
| {"'nonce-yay'", false}, |
| {"'strict-dynamic'", false}, |
| {"'sha512-321cba' http://example1.com/foo/", false}, |
| {"http://example1.com/foo/ 'sha512-321cba'", false}, |
| {"http://example1.com/foo/ 'nonce-yay'", false}, |
| {"'self' 'sha512-321cba' http://example1.com/foo/", false}, |
| {"'self' http://example1.com/foo/ 'sha512-321cba'", false}, |
| {"'self' http://example1.com/foo/ 'nonce-yay'", false}, |
| {"'sha512-321cba' 'nonce-yay'", false}, |
| {"http://example1.com/foo/ 'sha512-321cba' 'nonce-yay'", false}, |
| {"http://example1.com/foo/ 'sha512-321cba' 'nonce-yay'", false}, |
| {" 'sha512-321cba' 'nonce-yay' 'strict-dynamic'", false}, |
| }; |
| |
| for (const auto& test : cases) { |
| SCOPED_TRACE(test.sources); |
| network::mojom::blink::CSPSourceListPtr script_src = |
| CSPSourceListParse("script-src", test.sources, csp.Get()); |
| EXPECT_EQ(CSPSourceListIsSelf(*script_src), test.expected); |
| |
| network::mojom::blink::CSPSourceListPtr form_action = |
| CSPSourceListParse("form-action", test.sources, csp.Get()); |
| EXPECT_EQ(CSPSourceListIsSelf(*form_action), test.expected); |
| |
| network::mojom::blink::CSPSourceListPtr frame_src = |
| CSPSourceListParse("frame-src", test.sources, csp.Get()); |
| EXPECT_EQ(CSPSourceListIsSelf(*frame_src), test.expected); |
| } |
| } |
| |
| TEST_F(SourceListDirectiveTest, AllowsURLBasedMatching) { |
| struct TestCase { |
| String sources; |
| bool expected; |
| } cases[] = { |
| // No URL-based matching. |
| {"'none'", false}, |
| {"'sha256-abcdefg'", false}, |
| {"'nonce-abc'", false}, |
| {"'nonce-abce' 'sha256-abcdefg'", false}, |
| |
| // Strict-dynamic. |
| {"'sha256-abcdefg' 'strict-dynamic'", false}, |
| {"'nonce-abce' 'strict-dynamic'", false}, |
| {"'nonce-abce' 'sha256-abcdefg' 'strict-dynamic'", false}, |
| {"'sha256-abcdefg' 'strict-dynamic' https:", false}, |
| {"'nonce-abce' 'strict-dynamic' http://example.test", false}, |
| {"'nonce-abce' 'sha256-abcdefg' 'strict-dynamic' *://example.test", |
| false}, |
| |
| // URL-based. |
| {"*", true}, |
| {"'self'", true}, |
| {"http:", true}, |
| {"http: https:", true}, |
| {"http: 'none'", true}, |
| {"http: https: 'none'", true}, |
| {"'sha256-abcdefg' https://example.test", true}, |
| {"'nonce-abc' https://example.test", true}, |
| {"'nonce-abce' 'sha256-abcdefg' https://example.test", true}, |
| {"'sha256-abcdefg' https://example.test 'none'", true}, |
| {"'nonce-abc' https://example.test 'none'", true}, |
| {"'nonce-abce' 'sha256-abcdefg' https://example.test 'none'", true}, |
| |
| }; |
| |
| for (const auto& test : cases) { |
| SCOPED_TRACE(test.sources); |
| network::mojom::blink::CSPSourceListPtr script_src = |
| CSPSourceListParse("script-src", test.sources, csp.Get()); |
| EXPECT_EQ(CSPSourceListAllowsURLBasedMatching(*script_src), test.expected); |
| |
| network::mojom::blink::CSPSourceListPtr form_action = |
| CSPSourceListParse("form-action", test.sources, csp.Get()); |
| EXPECT_EQ(CSPSourceListAllowsURLBasedMatching(*form_action), test.expected); |
| |
| network::mojom::blink::CSPSourceListPtr frame_src = |
| CSPSourceListParse("frame-src", test.sources, csp.Get()); |
| EXPECT_EQ(CSPSourceListAllowsURLBasedMatching(*frame_src), test.expected); |
| } |
| } |
| |
| TEST_F(SourceListDirectiveTest, ParseHost) { |
| struct TestCase { |
| String sources; |
| bool expected; |
| } cases[] = { |
| // Wildcard. |
| {"*", true}, |
| {"*.", false}, |
| {"*.a", true}, |
| {"a.*.a", false}, |
| {"a.*", false}, |
| |
| // Dots. |
| {"a.b.c", true}, |
| {"a.b.", false}, |
| {".b.c", false}, |
| {"a..c", false}, |
| |
| // Valid/Invalid characters. |
| {"az09-", true}, |
| {"+", false}, |
| }; |
| |
| for (const auto& test : cases) { |
| network::mojom::blink::CSPSourceListPtr parsed = |
| CSPSourceListParse("default-src", test.sources, csp.Get()); |
| EXPECT_EQ(CSPSourceListIsNone(*parsed), !test.expected) |
| << "CSPSourceListParse failed to parse: " << test.sources; |
| } |
| } |
| |
| TEST_F(SourceListDirectiveTest, AllowHostWildcard) { |
| KURL base; |
| // When the host-part is "*", the port must still be checked. |
| // See crbug.com/682673. |
| { |
| String sources = "http://*:111"; |
| network::mojom::blink::CSPSourceListPtr source_list = |
| CSPSourceListParse("default-src", sources, csp.Get()); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://a.com:111"))); |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://a.com:222"))); |
| } |
| // When the host-part is "*", the path must still be checked. |
| // See crbug.com/682673. |
| { |
| String sources = "http://*/welcome.html"; |
| network::mojom::blink::CSPSourceListPtr source_list = |
| CSPSourceListParse("default-src", sources, csp.Get()); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://a.com/welcome.html"))); |
| EXPECT_FALSE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://a.com/passwords.txt"))); |
| } |
| // When the host-part is "*" and the expression-source is not "*", then every |
| // host are allowed. See crbug.com/682673. |
| { |
| String sources = "http://*"; |
| network::mojom::blink::CSPSourceListPtr source_list = |
| CSPSourceListParse("default-src", sources, csp.Get()); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://a.com"))); |
| } |
| } |
| |
| TEST_F(SourceListDirectiveTest, AllowHostMixedCase) { |
| KURL base; |
| // Non-wildcard sources should match hosts case-insensitively. |
| { |
| String sources = "http://ExAmPle.com"; |
| network::mojom::blink::CSPSourceListPtr source_list = |
| CSPSourceListParse("default-src", sources, csp.Get()); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://example.com"))); |
| } |
| // Wildcard sources should match hosts case-insensitively. |
| { |
| String sources = "http://*.ExAmPle.com"; |
| network::mojom::blink::CSPSourceListPtr source_list = |
| CSPSourceListParse("default-src", sources, csp.Get()); |
| EXPECT_TRUE(CSPSourceListAllows(*source_list, *self_source, |
| KURL(base, "http://www.example.com"))); |
| } |
| } |
| |
| TEST_F(SourceListDirectiveTest, AllowNonce) { |
| struct TestCase { |
| const char* directive_value; |
| const char* nonce; |
| bool expected; |
| } cases[] = { |
| {"'self'", "yay", false}, |
| {"'self'", "boo", false}, |
| {"'nonce-yay'", "yay", true}, |
| {"'nonce-yay'", "boo", false}, |
| {"'nonce-yay' 'nonce-boo'", "yay", true}, |
| {"'nonce-yay' 'nonce-boo'", "boo", true}, |
| }; |
| |
| for (const auto& test : cases) { |
| network::mojom::blink::CSPSourceListPtr source_list = |
| CSPSourceListParse("script-src", test.directive_value, csp.Get()); |
| EXPECT_EQ(test.expected, CSPSourceListAllowNonce(*source_list, test.nonce)); |
| // Empty/null strings are always not present. |
| EXPECT_FALSE(CSPSourceListAllowNonce(*source_list, "")); |
| EXPECT_FALSE(CSPSourceListAllowNonce(*source_list, String())); |
| } |
| } |
| |
| } // namespace blink |