1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
6 
7 #include "base/test/scoped_feature_list.h"
8 #include "services/network/public/cpp/features.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "third_party/blink/public/common/security_context/insecure_request_policy.h"
11 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
12 #include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom-blink.h"
13 #include "third_party/blink/renderer/core/dom/document.h"
14 #include "third_party/blink/renderer/core/dom/document_init.h"
15 #include "third_party/blink/renderer/core/frame/csp/csp_directive_list.h"
16 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
17 #include "third_party/blink/renderer/core/html/html_script_element.h"
18 #include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
19 #include "third_party/blink/renderer/core/testing/null_execution_context.h"
20 #include "third_party/blink/renderer/platform/crypto.h"
21 #include "third_party/blink/renderer/platform/heap/heap.h"
22 #include "third_party/blink/renderer/platform/loader/fetch/integrity_metadata.h"
23 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
24 #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
25 #include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
26 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
27 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
28 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
29 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
30 
31 namespace blink {
32 
33 using network::mojom::ContentSecurityPolicySource;
34 using network::mojom::ContentSecurityPolicyType;
35 
36 class ContentSecurityPolicyTest : public testing::Test {
37  public:
ContentSecurityPolicyTest()38   ContentSecurityPolicyTest()
39       : csp(MakeGarbageCollected<ContentSecurityPolicy>()),
40         secure_url("https://example.test/image.png"),
41         secure_origin(SecurityOrigin::Create(secure_url)) {}
42 
43  protected:
SetUp()44   void SetUp() override { execution_context = CreateExecutionContext(); }
45 
CreateExecutionContext()46   NullExecutionContext* CreateExecutionContext() {
47     NullExecutionContext* context =
48         MakeGarbageCollected<NullExecutionContext>();
49     context->SetUpSecurityContextForTesting();
50     context->GetSecurityContext().SetSecurityOriginForTesting(secure_origin);
51     return context;
52   }
53 
54   Persistent<ContentSecurityPolicy> csp;
55   KURL secure_url;
56   scoped_refptr<SecurityOrigin> secure_origin;
57   Persistent<NullExecutionContext> execution_context;
58 };
59 
TEST_F(ContentSecurityPolicyTest,ParseInsecureRequestPolicy)60 TEST_F(ContentSecurityPolicyTest, ParseInsecureRequestPolicy) {
61   struct TestCase {
62     const char* header;
63     mojom::blink::InsecureRequestPolicy expected_policy;
64   } cases[] = {
65       {"default-src 'none'",
66        mojom::blink::InsecureRequestPolicy::kLeaveInsecureRequestsAlone},
67       {"upgrade-insecure-requests",
68        mojom::blink::InsecureRequestPolicy::kUpgradeInsecureRequests},
69       {"block-all-mixed-content",
70        mojom::blink::InsecureRequestPolicy::kBlockAllMixedContent},
71       {"upgrade-insecure-requests; block-all-mixed-content",
72        mojom::blink::InsecureRequestPolicy::kUpgradeInsecureRequests |
73            mojom::blink::InsecureRequestPolicy::kBlockAllMixedContent},
74       {"upgrade-insecure-requests, block-all-mixed-content",
75        mojom::blink::InsecureRequestPolicy::kUpgradeInsecureRequests |
76            mojom::blink::InsecureRequestPolicy::kBlockAllMixedContent}};
77 
78   // Enforced
79   for (const auto& test : cases) {
80     SCOPED_TRACE(testing::Message()
81                  << "[Enforce] Header: `" << test.header << "`");
82     csp = MakeGarbageCollected<ContentSecurityPolicy>();
83     csp->DidReceiveHeader(test.header, ContentSecurityPolicyType::kEnforce,
84                           ContentSecurityPolicySource::kHTTP);
85     EXPECT_EQ(test.expected_policy, csp->GetInsecureRequestPolicy());
86 
87     auto dummy = std::make_unique<DummyPageHolder>();
88     dummy->GetDocument().SetURL(secure_url);
89     auto& security_context =
90         dummy->GetFrame().DomWindow()->GetSecurityContext();
91     security_context.SetSecurityOriginForTesting(secure_origin);
92 
93     csp->BindToDelegate(
94         dummy->GetFrame().DomWindow()->GetContentSecurityPolicyDelegate());
95     EXPECT_EQ(test.expected_policy,
96               security_context.GetInsecureRequestPolicy());
97     bool expect_upgrade =
98         (test.expected_policy &
99          mojom::blink::InsecureRequestPolicy::kUpgradeInsecureRequests) !=
100         mojom::blink::InsecureRequestPolicy::kLeaveInsecureRequestsAlone;
101     EXPECT_EQ(expect_upgrade,
102               security_context.InsecureNavigationsToUpgrade().Contains(
103                   dummy->GetDocument().Url().Host().Impl()->GetHash()));
104   }
105 
106   // Report-Only
107   for (const auto& test : cases) {
108     SCOPED_TRACE(testing::Message()
109                  << "[Report-Only] Header: `" << test.header << "`");
110     csp = MakeGarbageCollected<ContentSecurityPolicy>();
111     csp->DidReceiveHeader(test.header, ContentSecurityPolicyType::kReport,
112                           ContentSecurityPolicySource::kHTTP);
113     EXPECT_EQ(mojom::blink::InsecureRequestPolicy::kLeaveInsecureRequestsAlone,
114               csp->GetInsecureRequestPolicy());
115 
116     execution_context = CreateExecutionContext();
117     execution_context->GetSecurityContext().SetSecurityOrigin(secure_origin);
118     csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
119     EXPECT_EQ(
120         mojom::blink::InsecureRequestPolicy::kLeaveInsecureRequestsAlone,
121         execution_context->GetSecurityContext().GetInsecureRequestPolicy());
122     EXPECT_FALSE(execution_context->GetSecurityContext()
123                      .InsecureNavigationsToUpgrade()
124                      .Contains(secure_origin->Host().Impl()->GetHash()));
125   }
126 }
127 
TEST_F(ContentSecurityPolicyTest,CopyStateFrom)128 TEST_F(ContentSecurityPolicyTest, CopyStateFrom) {
129   csp->DidReceiveHeader("script-src 'none'; plugin-types application/x-type-1",
130                         ContentSecurityPolicyType::kReport,
131                         ContentSecurityPolicySource::kHTTP);
132   csp->DidReceiveHeader("img-src http://example.com",
133                         ContentSecurityPolicyType::kReport,
134                         ContentSecurityPolicySource::kHTTP);
135 
136   const KURL example_url("http://example.com");
137   const KURL not_example_url("http://not-example.com");
138 
139   auto* csp2 = MakeGarbageCollected<ContentSecurityPolicy>();
140   csp2->CopyStateFrom(csp.Get());
141   EXPECT_FALSE(csp2->AllowScriptFromSource(
142       example_url, String(), IntegrityMetadataSet(), kParserInserted,
143       example_url, ResourceRequest::RedirectStatus::kNoRedirect,
144       ReportingDisposition::kSuppressReporting,
145       ContentSecurityPolicy::CheckHeaderType::kCheckReportOnly));
146   EXPECT_TRUE(csp2->AllowPluginType("application/x-type-1",
147                                     "application/x-type-1", example_url,
148                                     ReportingDisposition::kSuppressReporting));
149   EXPECT_TRUE(csp2->AllowImageFromSource(
150       example_url, example_url, ResourceRequest::RedirectStatus::kNoRedirect,
151       ReportingDisposition::kSuppressReporting,
152       ContentSecurityPolicy::CheckHeaderType::kCheckReportOnly));
153   EXPECT_FALSE(csp2->AllowImageFromSource(
154       not_example_url, not_example_url,
155       ResourceRequest::RedirectStatus::kNoRedirect,
156       ReportingDisposition::kSuppressReporting,
157       ContentSecurityPolicy::CheckHeaderType::kCheckReportOnly));
158   EXPECT_FALSE(csp2->AllowPluginType("application/x-type-2",
159                                      "application/x-type-2", example_url,
160                                      ReportingDisposition::kSuppressReporting));
161 }
162 
TEST_F(ContentSecurityPolicyTest,CopyPluginTypesFrom)163 TEST_F(ContentSecurityPolicyTest, CopyPluginTypesFrom) {
164   csp->DidReceiveHeader("script-src 'none'; plugin-types application/x-type-1",
165                         ContentSecurityPolicyType::kEnforce,
166                         ContentSecurityPolicySource::kHTTP);
167   csp->DidReceiveHeader("img-src http://example.com",
168                         ContentSecurityPolicyType::kEnforce,
169                         ContentSecurityPolicySource::kHTTP);
170 
171   const KURL example_url("http://example.com");
172   const KURL not_example_url("http://not-example.com");
173 
174   auto* csp2 = MakeGarbageCollected<ContentSecurityPolicy>();
175   csp2->CopyPluginTypesFrom(csp.Get());
176   EXPECT_TRUE(csp2->AllowScriptFromSource(
177       example_url, String(), IntegrityMetadataSet(), kParserInserted,
178       example_url, ResourceRequest::RedirectStatus::kNoRedirect,
179       ReportingDisposition::kSuppressReporting));
180   EXPECT_TRUE(csp2->AllowPluginType("application/x-type-1",
181                                     "application/x-type-1", example_url,
182                                     ReportingDisposition::kSuppressReporting));
183   EXPECT_TRUE(csp2->AllowImageFromSource(
184       example_url, example_url, ResourceRequest::RedirectStatus::kNoRedirect,
185       ReportingDisposition::kSuppressReporting));
186   EXPECT_TRUE(
187       csp2->AllowImageFromSource(not_example_url, not_example_url,
188                                  ResourceRequest::RedirectStatus::kNoRedirect,
189                                  ReportingDisposition::kSuppressReporting));
190   EXPECT_FALSE(csp2->AllowPluginType("application/x-type-2",
191                                      "application/x-type-2", example_url,
192                                      ReportingDisposition::kSuppressReporting));
193 }
194 
TEST_F(ContentSecurityPolicyTest,IsActiveForConnectionsWithConnectSrc)195 TEST_F(ContentSecurityPolicyTest, IsActiveForConnectionsWithConnectSrc) {
196   EXPECT_FALSE(csp->IsActiveForConnections());
197   csp->DidReceiveHeader("connect-src 'none';",
198                         ContentSecurityPolicyType::kEnforce,
199                         ContentSecurityPolicySource::kHTTP);
200   EXPECT_TRUE(csp->IsActiveForConnections());
201 }
202 
TEST_F(ContentSecurityPolicyTest,IsActiveForConnectionsWithDefaultSrc)203 TEST_F(ContentSecurityPolicyTest, IsActiveForConnectionsWithDefaultSrc) {
204   EXPECT_FALSE(csp->IsActiveForConnections());
205   csp->DidReceiveHeader("default-src 'none';",
206                         ContentSecurityPolicyType::kEnforce,
207                         ContentSecurityPolicySource::kHTTP);
208   EXPECT_TRUE(csp->IsActiveForConnections());
209 }
210 
211 // Tests that sandbox directives are discarded from policies
212 // delivered in <meta> elements.
TEST_F(ContentSecurityPolicyTest,SandboxInMeta)213 TEST_F(ContentSecurityPolicyTest, SandboxInMeta) {
214   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
215   EXPECT_EQ(network::mojom::blink::WebSandboxFlags::kNone,
216             csp->GetSandboxMask());
217   csp->DidReceiveHeader("sandbox;", ContentSecurityPolicyType::kEnforce,
218                         ContentSecurityPolicySource::kMeta);
219   EXPECT_EQ(network::mojom::blink::WebSandboxFlags::kNone,
220             csp->GetSandboxMask());
221   execution_context->GetSecurityContext().ApplySandboxFlags(
222       network::mojom::blink::WebSandboxFlags::kAll);
223   csp->DidReceiveHeader("sandbox;", ContentSecurityPolicyType::kEnforce,
224                         ContentSecurityPolicySource::kHTTP);
225   EXPECT_EQ(network::mojom::blink::WebSandboxFlags::kAll,
226             csp->GetSandboxMask());
227 }
228 
229 // Tests that report-uri directives are discarded from policies
230 // delivered in <meta> elements.
TEST_F(ContentSecurityPolicyTest,ReportURIInMeta)231 TEST_F(ContentSecurityPolicyTest, ReportURIInMeta) {
232   String policy = "img-src 'none'; report-uri http://foo.test";
233   Vector<UChar> characters;
234   policy.AppendTo(characters);
235   const UChar* begin = characters.data();
236   const UChar* end = begin + characters.size();
237   CSPDirectiveList* directive_list(CSPDirectiveList::Create(
238       csp, begin, end, ContentSecurityPolicyType::kEnforce,
239       ContentSecurityPolicySource::kMeta));
240   EXPECT_TRUE(directive_list->ReportEndpoints().IsEmpty());
241   directive_list = CSPDirectiveList::Create(csp, begin, end,
242                                             ContentSecurityPolicyType::kEnforce,
243                                             ContentSecurityPolicySource::kHTTP);
244   EXPECT_FALSE(directive_list->ReportEndpoints().IsEmpty());
245 }
246 
247 // Tests that object-src directives are applied to a request to load a
248 // plugin, but not to subresource requests that the plugin itself
249 // makes. https://crbug.com/603952
TEST_F(ContentSecurityPolicyTest,ObjectSrc)250 TEST_F(ContentSecurityPolicyTest, ObjectSrc) {
251   const KURL url("https://example.test");
252   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
253   csp->DidReceiveHeader("object-src 'none';",
254                         ContentSecurityPolicyType::kEnforce,
255                         ContentSecurityPolicySource::kMeta);
256   EXPECT_FALSE(csp->AllowRequest(mojom::blink::RequestContextType::OBJECT,
257                                  network::mojom::RequestDestination::kEmpty,
258                                  url, String(), IntegrityMetadataSet(),
259                                  kParserInserted, url,
260                                  ResourceRequest::RedirectStatus::kNoRedirect,
261                                  ReportingDisposition::kSuppressReporting));
262   EXPECT_FALSE(csp->AllowRequest(mojom::blink::RequestContextType::EMBED,
263                                  network::mojom::RequestDestination::kEmbed,
264                                  url, String(), IntegrityMetadataSet(),
265                                  kParserInserted, url,
266                                  ResourceRequest::RedirectStatus::kNoRedirect,
267                                  ReportingDisposition::kSuppressReporting));
268   EXPECT_TRUE(csp->AllowRequest(mojom::blink::RequestContextType::PLUGIN,
269                                 network::mojom::RequestDestination::kEmpty, url,
270                                 String(), IntegrityMetadataSet(),
271                                 kParserInserted, url,
272                                 ResourceRequest::RedirectStatus::kNoRedirect,
273                                 ReportingDisposition::kSuppressReporting));
274 }
275 
TEST_F(ContentSecurityPolicyTest,ConnectSrc)276 TEST_F(ContentSecurityPolicyTest, ConnectSrc) {
277   const KURL url("https://example.test");
278   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
279   csp->DidReceiveHeader("connect-src 'none';",
280                         ContentSecurityPolicyType::kEnforce,
281                         ContentSecurityPolicySource::kMeta);
282   EXPECT_FALSE(csp->AllowRequest(mojom::blink::RequestContextType::SUBRESOURCE,
283                                  network::mojom::RequestDestination::kEmpty,
284                                  url, String(), IntegrityMetadataSet(),
285                                  kParserInserted, url,
286                                  ResourceRequest::RedirectStatus::kNoRedirect,
287                                  ReportingDisposition::kSuppressReporting));
288   EXPECT_FALSE(
289       csp->AllowRequest(mojom::blink::RequestContextType::XML_HTTP_REQUEST,
290                         network::mojom::RequestDestination::kEmpty, url,
291                         String(), IntegrityMetadataSet(), kParserInserted, url,
292                         ResourceRequest::RedirectStatus::kNoRedirect,
293                         ReportingDisposition::kSuppressReporting));
294   EXPECT_FALSE(csp->AllowRequest(mojom::blink::RequestContextType::BEACON,
295                                  network::mojom::RequestDestination::kEmpty,
296                                  url, String(), IntegrityMetadataSet(),
297                                  kParserInserted, url,
298                                  ResourceRequest::RedirectStatus::kNoRedirect,
299                                  ReportingDisposition::kSuppressReporting));
300   EXPECT_FALSE(csp->AllowRequest(mojom::blink::RequestContextType::FETCH,
301                                  network::mojom::RequestDestination::kEmpty,
302                                  url, String(), IntegrityMetadataSet(),
303                                  kParserInserted, url,
304                                  ResourceRequest::RedirectStatus::kNoRedirect,
305                                  ReportingDisposition::kSuppressReporting));
306   EXPECT_TRUE(csp->AllowRequest(mojom::blink::RequestContextType::PLUGIN,
307                                 network::mojom::RequestDestination::kEmpty, url,
308                                 String(), IntegrityMetadataSet(),
309                                 kParserInserted, url,
310                                 ResourceRequest::RedirectStatus::kNoRedirect,
311                                 ReportingDisposition::kSuppressReporting));
312 }
313 
TEST_F(ContentSecurityPolicyTest,NonceSinglePolicy)314 TEST_F(ContentSecurityPolicyTest, NonceSinglePolicy) {
315   struct TestCase {
316     const char* policy;
317     const char* url;
318     const char* nonce;
319     bool allowed;
320   } cases[] = {
321       {"script-src 'nonce-yay'", "https://example.com/js", "", false},
322       {"script-src 'nonce-yay'", "https://example.com/js", "yay", true},
323       {"script-src https://example.com", "https://example.com/js", "", true},
324       {"script-src https://example.com", "https://example.com/js", "yay", true},
325       {"script-src https://example.com 'nonce-yay'",
326        "https://not.example.com/js", "", false},
327       {"script-src https://example.com 'nonce-yay'",
328        "https://not.example.com/js", "yay", true},
329   };
330 
331   for (const auto& test : cases) {
332     SCOPED_TRACE(testing::Message()
333                  << "Policy: `" << test.policy << "`, URL: `" << test.url
334                  << "`, Nonce: `" << test.nonce << "`");
335     const KURL resource(test.url);
336 
337     unsigned expected_reports = test.allowed ? 0u : 1u;
338 
339     // Single enforce-mode policy should match `test.expected`:
340     Persistent<ContentSecurityPolicy> policy =
341         MakeGarbageCollected<ContentSecurityPolicy>();
342     policy->BindToDelegate(
343         execution_context->GetContentSecurityPolicyDelegate());
344     policy->DidReceiveHeader(test.policy, ContentSecurityPolicyType::kEnforce,
345                              ContentSecurityPolicySource::kHTTP);
346     EXPECT_EQ(test.allowed,
347               policy->AllowScriptFromSource(
348                   resource, String(test.nonce), IntegrityMetadataSet(),
349                   kParserInserted, resource,
350                   ResourceRequest::RedirectStatus::kNoRedirect));
351     // If this is expected to generate a violation, we should have sent a
352     // report.
353     EXPECT_EQ(expected_reports, policy->violation_reports_sent_.size());
354 
355     // Single report-mode policy should always be `true`:
356     policy = MakeGarbageCollected<ContentSecurityPolicy>();
357     policy->BindToDelegate(
358         execution_context->GetContentSecurityPolicyDelegate());
359     policy->DidReceiveHeader(test.policy, ContentSecurityPolicyType::kReport,
360                              ContentSecurityPolicySource::kHTTP);
361     EXPECT_TRUE(policy->AllowScriptFromSource(
362         resource, String(test.nonce), IntegrityMetadataSet(), kParserInserted,
363         resource, ResourceRequest::RedirectStatus::kNoRedirect,
364         ReportingDisposition::kReport,
365         ContentSecurityPolicy::CheckHeaderType::kCheckReportOnly));
366     // If this is expected to generate a violation, we should have sent a
367     // report, even though we don't deny access in `allowScriptFromSource`:
368     EXPECT_EQ(expected_reports, policy->violation_reports_sent_.size());
369   }
370 }
371 
TEST_F(ContentSecurityPolicyTest,NonceInline)372 TEST_F(ContentSecurityPolicyTest, NonceInline) {
373   struct TestCase {
374     const char* policy;
375     const char* nonce;
376     bool allowed;
377   } cases[] = {
378       {"'unsafe-inline'", "", true},
379       {"'unsafe-inline'", "yay", true},
380       {"'nonce-yay'", "", false},
381       {"'nonce-yay'", "yay", true},
382       {"'unsafe-inline' 'nonce-yay'", "", false},
383       {"'unsafe-inline' 'nonce-yay'", "yay", true},
384   };
385 
386   String context_url;
387   String content;
388   WTF::OrdinalNumber context_line;
389 
390   // We need document for HTMLScriptElement tests.
391   auto dummy = std::make_unique<DummyPageHolder>();
392   auto* window = dummy->GetFrame().DomWindow();
393   window->GetSecurityContext().SetSecurityOriginForTesting(secure_origin);
394 
395   for (const auto& test : cases) {
396     SCOPED_TRACE(testing::Message() << "Policy: `" << test.policy
397                                     << "`, Nonce: `" << test.nonce << "`");
398 
399     unsigned expected_reports = test.allowed ? 0u : 1u;
400     auto* element = MakeGarbageCollected<HTMLScriptElement>(
401         *window->document(), CreateElementFlags());
402 
403     // Enforce 'script-src'
404     Persistent<ContentSecurityPolicy> policy =
405         MakeGarbageCollected<ContentSecurityPolicy>();
406     policy->BindToDelegate(window->GetContentSecurityPolicyDelegate());
407     policy->DidReceiveHeader(String("script-src ") + test.policy,
408                              ContentSecurityPolicyType::kEnforce,
409                              ContentSecurityPolicySource::kHTTP);
410     EXPECT_EQ(test.allowed,
411               policy->AllowInline(ContentSecurityPolicy::InlineType::kScript,
412                                   element, content, String(test.nonce),
413                                   context_url, context_line));
414     EXPECT_EQ(expected_reports, policy->violation_reports_sent_.size());
415 
416     // Enforce 'style-src'
417     policy = MakeGarbageCollected<ContentSecurityPolicy>();
418     policy->BindToDelegate(window->GetContentSecurityPolicyDelegate());
419     policy->DidReceiveHeader(String("style-src ") + test.policy,
420                              ContentSecurityPolicyType::kEnforce,
421                              ContentSecurityPolicySource::kHTTP);
422     EXPECT_EQ(test.allowed,
423               policy->AllowInline(ContentSecurityPolicy::InlineType::kStyle,
424                                   element, content, String(test.nonce),
425                                   context_url, context_line));
426     EXPECT_EQ(expected_reports, policy->violation_reports_sent_.size());
427 
428     // Report 'script-src'
429     policy = MakeGarbageCollected<ContentSecurityPolicy>();
430     policy->BindToDelegate(window->GetContentSecurityPolicyDelegate());
431     policy->DidReceiveHeader(String("script-src ") + test.policy,
432                              ContentSecurityPolicyType::kReport,
433                              ContentSecurityPolicySource::kHTTP);
434     EXPECT_TRUE(policy->AllowInline(ContentSecurityPolicy::InlineType::kScript,
435                                     element, content, String(test.nonce),
436                                     context_url, context_line));
437     EXPECT_EQ(expected_reports, policy->violation_reports_sent_.size());
438 
439     // Report 'style-src'
440     policy = MakeGarbageCollected<ContentSecurityPolicy>();
441     policy->BindToDelegate(window->GetContentSecurityPolicyDelegate());
442     policy->DidReceiveHeader(String("style-src ") + test.policy,
443                              ContentSecurityPolicyType::kReport,
444                              ContentSecurityPolicySource::kHTTP);
445     EXPECT_TRUE(policy->AllowInline(ContentSecurityPolicy::InlineType::kStyle,
446                                     element, content, String(test.nonce),
447                                     context_url, context_line));
448     EXPECT_EQ(expected_reports, policy->violation_reports_sent_.size());
449   }
450 }
451 
TEST_F(ContentSecurityPolicyTest,NonceMultiplePolicy)452 TEST_F(ContentSecurityPolicyTest, NonceMultiplePolicy) {
453   struct TestCase {
454     const char* policy1;
455     const char* policy2;
456     const char* url;
457     const char* nonce;
458     bool allowed1;
459     bool allowed2;
460   } cases[] = {
461       // Passes both:
462       {"script-src 'nonce-yay'", "script-src 'nonce-yay'",
463        "https://example.com/js", "yay", true, true},
464       {"script-src https://example.com", "script-src 'nonce-yay'",
465        "https://example.com/js", "yay", true, true},
466       {"script-src 'nonce-yay'", "script-src https://example.com",
467        "https://example.com/js", "yay", true, true},
468       {"script-src https://example.com 'nonce-yay'",
469        "script-src https://example.com 'nonce-yay'", "https://example.com/js",
470        "yay", true, true},
471       {"script-src https://example.com 'nonce-yay'",
472        "script-src https://example.com 'nonce-yay'", "https://example.com/js",
473        "", true, true},
474       {"script-src https://example.com",
475        "script-src https://example.com 'nonce-yay'", "https://example.com/js",
476        "yay", true, true},
477       {"script-src https://example.com 'nonce-yay'",
478        "script-src https://example.com", "https://example.com/js", "yay", true,
479        true},
480 
481       // Fails one:
482       {"script-src 'nonce-yay'", "script-src https://example.com",
483        "https://example.com/js", "", false, true},
484       {"script-src 'nonce-yay'", "script-src 'none'", "https://example.com/js",
485        "yay", true, false},
486       {"script-src 'nonce-yay'", "script-src https://not.example.com",
487        "https://example.com/js", "yay", true, false},
488 
489       // Fails both:
490       {"script-src 'nonce-yay'", "script-src https://example.com",
491        "https://not.example.com/js", "", false, false},
492       {"script-src https://example.com", "script-src 'nonce-yay'",
493        "https://not.example.com/js", "", false, false},
494       {"script-src 'nonce-yay'", "script-src 'none'",
495        "https://not.example.com/js", "boo", false, false},
496       {"script-src 'nonce-yay'", "script-src https://not.example.com",
497        "https://example.com/js", "", false, false},
498   };
499 
500   for (const auto& test : cases) {
501     SCOPED_TRACE(testing::Message() << "Policy: `" << test.policy1 << "`/`"
502                                     << test.policy2 << "`, URL: `" << test.url
503                                     << "`, Nonce: `" << test.nonce << "`");
504     const KURL resource(test.url);
505 
506     unsigned expected_reports =
507         test.allowed1 != test.allowed2 ? 1u : (test.allowed1 ? 0u : 2u);
508 
509     // Enforce / Report
510     Persistent<ContentSecurityPolicy> policy =
511         MakeGarbageCollected<ContentSecurityPolicy>();
512     policy->BindToDelegate(
513         execution_context->GetContentSecurityPolicyDelegate());
514     policy->DidReceiveHeader(test.policy1, ContentSecurityPolicyType::kEnforce,
515                              ContentSecurityPolicySource::kHTTP);
516     policy->DidReceiveHeader(test.policy2, ContentSecurityPolicyType::kReport,
517                              ContentSecurityPolicySource::kHTTP);
518     EXPECT_EQ(test.allowed1,
519               policy->AllowScriptFromSource(
520                   resource, String(test.nonce), IntegrityMetadataSet(),
521                   kParserInserted, resource,
522                   ResourceRequest::RedirectStatus::kNoRedirect,
523                   ReportingDisposition::kReport,
524                   ContentSecurityPolicy::CheckHeaderType::kCheckEnforce));
525     EXPECT_TRUE(policy->AllowScriptFromSource(
526         resource, String(test.nonce), IntegrityMetadataSet(), kParserInserted,
527         resource, ResourceRequest::RedirectStatus::kNoRedirect,
528         ReportingDisposition::kReport,
529         ContentSecurityPolicy::CheckHeaderType::kCheckReportOnly));
530     EXPECT_EQ(expected_reports, policy->violation_reports_sent_.size());
531 
532     // Report / Enforce
533     policy = MakeGarbageCollected<ContentSecurityPolicy>();
534     policy->BindToDelegate(
535         execution_context->GetContentSecurityPolicyDelegate());
536     policy->DidReceiveHeader(test.policy1, ContentSecurityPolicyType::kReport,
537                              ContentSecurityPolicySource::kHTTP);
538     policy->DidReceiveHeader(test.policy2, ContentSecurityPolicyType::kEnforce,
539                              ContentSecurityPolicySource::kHTTP);
540     EXPECT_TRUE(policy->AllowScriptFromSource(
541         resource, String(test.nonce), IntegrityMetadataSet(), kParserInserted,
542         resource, ResourceRequest::RedirectStatus::kNoRedirect,
543         ReportingDisposition::kReport,
544         ContentSecurityPolicy::CheckHeaderType::kCheckReportOnly));
545     EXPECT_EQ(test.allowed2,
546               policy->AllowScriptFromSource(
547                   resource, String(test.nonce), IntegrityMetadataSet(),
548                   kParserInserted, resource,
549                   ResourceRequest::RedirectStatus::kNoRedirect,
550                   ReportingDisposition::kReport,
551                   ContentSecurityPolicy::CheckHeaderType::kCheckEnforce));
552     EXPECT_EQ(expected_reports, policy->violation_reports_sent_.size());
553 
554     // Enforce / Enforce
555     policy = MakeGarbageCollected<ContentSecurityPolicy>();
556     policy->BindToDelegate(
557         execution_context->GetContentSecurityPolicyDelegate());
558     policy->DidReceiveHeader(test.policy1, ContentSecurityPolicyType::kEnforce,
559                              ContentSecurityPolicySource::kHTTP);
560     policy->DidReceiveHeader(test.policy2, ContentSecurityPolicyType::kEnforce,
561                              ContentSecurityPolicySource::kHTTP);
562     EXPECT_EQ(test.allowed1 && test.allowed2,
563               policy->AllowScriptFromSource(
564                   resource, String(test.nonce), IntegrityMetadataSet(),
565                   kParserInserted, resource,
566                   ResourceRequest::RedirectStatus::kNoRedirect,
567                   ReportingDisposition::kReport,
568                   ContentSecurityPolicy::CheckHeaderType::kCheckEnforce));
569     EXPECT_EQ(expected_reports, policy->violation_reports_sent_.size());
570 
571     // Report / Report
572     policy = MakeGarbageCollected<ContentSecurityPolicy>();
573     policy->BindToDelegate(
574         execution_context->GetContentSecurityPolicyDelegate());
575     policy->DidReceiveHeader(test.policy1, ContentSecurityPolicyType::kReport,
576                              ContentSecurityPolicySource::kHTTP);
577     policy->DidReceiveHeader(test.policy2, ContentSecurityPolicyType::kReport,
578                              ContentSecurityPolicySource::kHTTP);
579     EXPECT_TRUE(policy->AllowScriptFromSource(
580         resource, String(test.nonce), IntegrityMetadataSet(), kParserInserted,
581         resource, ResourceRequest::RedirectStatus::kNoRedirect,
582         ReportingDisposition::kReport,
583         ContentSecurityPolicy::CheckHeaderType::kCheckReportOnly));
584     EXPECT_EQ(expected_reports, policy->violation_reports_sent_.size());
585   }
586 }
587 
TEST_F(ContentSecurityPolicyTest,ShouldEnforceEmbeddersPolicy)588 TEST_F(ContentSecurityPolicyTest, ShouldEnforceEmbeddersPolicy) {
589   struct TestCase {
590     const char* resource_url;
591     const bool inherits;
592   } cases[] = {
593       // Same-origin
594       {"https://example.test/index.html", true},
595       // Cross-origin
596       {"http://example.test/index.html", false},
597       {"http://example.test:8443/index.html", false},
598       {"https://example.test:8443/index.html", false},
599       {"http://not.example.test/index.html", false},
600       {"https://not.example.test/index.html", false},
601       {"https://not.example.test:8443/index.html", false},
602 
603       // Inherit
604       {"about:blank", true},
605       {"data:text/html,yay", true},
606       {"blob:https://example.test/bbe708f3-defd-4852-93b6-cf94e032f08d", true},
607       {"filesystem:http://example.test/temporary/index.html", true},
608   };
609 
610   for (const auto& test : cases) {
611     ResourceResponse response(KURL(test.resource_url));
612     EXPECT_EQ(ContentSecurityPolicy::ShouldEnforceEmbeddersPolicy(
613                   response, secure_origin.get()),
614               test.inherits);
615 
616     response.SetHttpHeaderField(http_names::kAllowCSPFrom, AtomicString("*"));
617     EXPECT_TRUE(ContentSecurityPolicy::ShouldEnforceEmbeddersPolicy(
618         response, secure_origin.get()));
619 
620     response.SetHttpHeaderField(http_names::kAllowCSPFrom,
621                                 AtomicString("* not a valid header"));
622     EXPECT_EQ(ContentSecurityPolicy::ShouldEnforceEmbeddersPolicy(
623                   response, secure_origin.get()),
624               test.inherits);
625 
626     response.SetHttpHeaderField(http_names::kAllowCSPFrom,
627                                 AtomicString("http://example.test"));
628     EXPECT_EQ(ContentSecurityPolicy::ShouldEnforceEmbeddersPolicy(
629                   response, secure_origin.get()),
630               test.inherits);
631 
632     response.SetHttpHeaderField(http_names::kAllowCSPFrom,
633                                 AtomicString("https://example.test"));
634     EXPECT_TRUE(ContentSecurityPolicy::ShouldEnforceEmbeddersPolicy(
635         response, secure_origin.get()));
636   }
637 }
638 
TEST_F(ContentSecurityPolicyTest,DirectiveType)639 TEST_F(ContentSecurityPolicyTest, DirectiveType) {
640   struct TestCase {
641     ContentSecurityPolicy::DirectiveType type;
642     const String& name;
643   } cases[] = {
644       {ContentSecurityPolicy::DirectiveType::kBaseURI, "base-uri"},
645       {ContentSecurityPolicy::DirectiveType::kBlockAllMixedContent,
646        "block-all-mixed-content"},
647       {ContentSecurityPolicy::DirectiveType::kChildSrc, "child-src"},
648       {ContentSecurityPolicy::DirectiveType::kConnectSrc, "connect-src"},
649       {ContentSecurityPolicy::DirectiveType::kDefaultSrc, "default-src"},
650       {ContentSecurityPolicy::DirectiveType::kFrameAncestors,
651        "frame-ancestors"},
652       {ContentSecurityPolicy::DirectiveType::kFrameSrc, "frame-src"},
653       {ContentSecurityPolicy::DirectiveType::kFontSrc, "font-src"},
654       {ContentSecurityPolicy::DirectiveType::kFormAction, "form-action"},
655       {ContentSecurityPolicy::DirectiveType::kImgSrc, "img-src"},
656       {ContentSecurityPolicy::DirectiveType::kManifestSrc, "manifest-src"},
657       {ContentSecurityPolicy::DirectiveType::kMediaSrc, "media-src"},
658       {ContentSecurityPolicy::DirectiveType::kNavigateTo, "navigate-to"},
659       {ContentSecurityPolicy::DirectiveType::kObjectSrc, "object-src"},
660       {ContentSecurityPolicy::DirectiveType::kPluginTypes, "plugin-types"},
661       {ContentSecurityPolicy::DirectiveType::kReportURI, "report-uri"},
662       {ContentSecurityPolicy::DirectiveType::kSandbox, "sandbox"},
663       {ContentSecurityPolicy::DirectiveType::kScriptSrc, "script-src"},
664       {ContentSecurityPolicy::DirectiveType::kScriptSrcAttr, "script-src-attr"},
665       {ContentSecurityPolicy::DirectiveType::kScriptSrcElem, "script-src-elem"},
666       {ContentSecurityPolicy::DirectiveType::kStyleSrc, "style-src"},
667       {ContentSecurityPolicy::DirectiveType::kStyleSrcAttr, "style-src-attr"},
668       {ContentSecurityPolicy::DirectiveType::kStyleSrcElem, "style-src-elem"},
669       {ContentSecurityPolicy::DirectiveType::kUpgradeInsecureRequests,
670        "upgrade-insecure-requests"},
671       {ContentSecurityPolicy::DirectiveType::kWorkerSrc, "worker-src"},
672   };
673 
674   EXPECT_EQ(ContentSecurityPolicy::DirectiveType::kUndefined,
675             ContentSecurityPolicy::GetDirectiveType("random"));
676 
677   for (const auto& test : cases) {
678     const String& name_from_type =
679         ContentSecurityPolicy::GetDirectiveName(test.type);
680     ContentSecurityPolicy::DirectiveType type_from_name =
681         ContentSecurityPolicy::GetDirectiveType(test.name);
682     EXPECT_EQ(name_from_type, test.name);
683     EXPECT_EQ(type_from_name, test.type);
684     EXPECT_EQ(test.type,
685               ContentSecurityPolicy::GetDirectiveType(name_from_type));
686     EXPECT_EQ(test.name,
687               ContentSecurityPolicy::GetDirectiveName(type_from_name));
688   }
689 }
690 
691 // TODO(antoniosartori): Remove this test and the function
692 // ContentSecurityPolicy::Subsumes when we remove the feature flag.
TEST_F(ContentSecurityPolicyTest,Subsumes)693 TEST_F(ContentSecurityPolicyTest, Subsumes) {
694   base::test::ScopedFeatureList feature_list;
695   feature_list.InitAndDisableFeature(network::features::kOutOfBlinkCSPEE);
696 
697   auto* other = MakeGarbageCollected<ContentSecurityPolicy>();
698   EXPECT_TRUE(csp->Subsumes(*other));
699   EXPECT_TRUE(other->Subsumes(*csp));
700 
701   csp->DidReceiveHeader("default-src http://example.com;",
702                         ContentSecurityPolicyType::kEnforce,
703                         ContentSecurityPolicySource::kHTTP);
704   // If this CSP is not empty, the other must not be empty either.
705   EXPECT_FALSE(csp->Subsumes(*other));
706   EXPECT_TRUE(other->Subsumes(*csp));
707 
708   // Report-only policies do not impact subsumption.
709   other->DidReceiveHeader("default-src http://example.com;",
710                           ContentSecurityPolicyType::kReport,
711                           ContentSecurityPolicySource::kHTTP);
712   EXPECT_FALSE(csp->Subsumes(*other));
713 
714   // CSPDirectiveLists have to subsume.
715   other->DidReceiveHeader("default-src http://example.com https://another.com;",
716                           ContentSecurityPolicyType::kEnforce,
717                           ContentSecurityPolicySource::kHTTP);
718   EXPECT_FALSE(csp->Subsumes(*other));
719 
720   // `other` is stricter than `this`.
721   other->DidReceiveHeader("default-src https://example.com;",
722                           ContentSecurityPolicyType::kEnforce,
723                           ContentSecurityPolicySource::kHTTP);
724   EXPECT_TRUE(csp->Subsumes(*other));
725 }
726 
TEST_F(ContentSecurityPolicyTest,RequestsAllowedWhenBypassingCSP)727 TEST_F(ContentSecurityPolicyTest, RequestsAllowedWhenBypassingCSP) {
728   const KURL base;
729   execution_context = CreateExecutionContext();
730   execution_context->GetSecurityContext().SetSecurityOrigin(
731       secure_origin);                     // https://example.com
732   execution_context->SetURL(secure_url);  // https://example.com
733   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
734   csp->DidReceiveHeader("default-src https://example.com",
735                         ContentSecurityPolicyType::kEnforce,
736                         ContentSecurityPolicySource::kHTTP);
737 
738   const KURL example_url("https://example.com/");
739   EXPECT_TRUE(csp->AllowRequest(mojom::blink::RequestContextType::OBJECT,
740                                 network::mojom::RequestDestination::kEmpty,
741                                 example_url, String(), IntegrityMetadataSet(),
742                                 kParserInserted, example_url,
743                                 ResourceRequest::RedirectStatus::kNoRedirect,
744                                 ReportingDisposition::kSuppressReporting));
745 
746   const KURL not_example_url("https://not-example.com/");
747   EXPECT_FALSE(csp->AllowRequest(
748       mojom::blink::RequestContextType::OBJECT,
749       network::mojom::RequestDestination::kEmpty, not_example_url, String(),
750       IntegrityMetadataSet(), kParserInserted, not_example_url,
751       ResourceRequest::RedirectStatus::kNoRedirect,
752       ReportingDisposition::kSuppressReporting));
753 
754   // Register "https" as bypassing CSP, which should now bypass it entirely
755   SchemeRegistry::RegisterURLSchemeAsBypassingContentSecurityPolicy("https");
756 
757   EXPECT_TRUE(csp->AllowRequest(mojom::blink::RequestContextType::OBJECT,
758                                 network::mojom::RequestDestination::kEmpty,
759                                 example_url, String(), IntegrityMetadataSet(),
760                                 kParserInserted, example_url,
761                                 ResourceRequest::RedirectStatus::kNoRedirect,
762                                 ReportingDisposition::kSuppressReporting));
763 
764   EXPECT_TRUE(csp->AllowRequest(
765       mojom::blink::RequestContextType::OBJECT,
766       network::mojom::RequestDestination::kEmpty, not_example_url, String(),
767       IntegrityMetadataSet(), kParserInserted, not_example_url,
768       ResourceRequest::RedirectStatus::kNoRedirect,
769       ReportingDisposition::kSuppressReporting));
770 
771   SchemeRegistry::RemoveURLSchemeRegisteredAsBypassingContentSecurityPolicy(
772       "https");
773 }
TEST_F(ContentSecurityPolicyTest,FilesystemAllowedWhenBypassingCSP)774 TEST_F(ContentSecurityPolicyTest, FilesystemAllowedWhenBypassingCSP) {
775   const KURL base;
776   execution_context = CreateExecutionContext();
777   execution_context->GetSecurityContext().SetSecurityOrigin(
778       secure_origin);                     // https://example.com
779   execution_context->SetURL(secure_url);  // https://example.com
780   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
781   csp->DidReceiveHeader("default-src https://example.com",
782                         ContentSecurityPolicyType::kEnforce,
783                         ContentSecurityPolicySource::kHTTP);
784 
785   const KURL example_url("filesystem:https://example.com/file.txt");
786   EXPECT_FALSE(csp->AllowRequest(mojom::blink::RequestContextType::OBJECT,
787                                  network::mojom::RequestDestination::kEmpty,
788                                  example_url, String(), IntegrityMetadataSet(),
789                                  kParserInserted, example_url,
790                                  ResourceRequest::RedirectStatus::kNoRedirect,
791                                  ReportingDisposition::kSuppressReporting));
792 
793   const KURL not_example_url("filesystem:https://not-example.com/file.txt");
794   EXPECT_FALSE(csp->AllowRequest(
795       mojom::blink::RequestContextType::OBJECT,
796       network::mojom::RequestDestination::kEmpty, not_example_url, String(),
797       IntegrityMetadataSet(), kParserInserted, not_example_url,
798       ResourceRequest::RedirectStatus::kNoRedirect,
799       ReportingDisposition::kSuppressReporting));
800 
801   // Register "https" as bypassing CSP, which should now bypass it entirely
802   SchemeRegistry::RegisterURLSchemeAsBypassingContentSecurityPolicy("https");
803 
804   EXPECT_TRUE(csp->AllowRequest(mojom::blink::RequestContextType::OBJECT,
805                                 network::mojom::RequestDestination::kEmpty,
806                                 example_url, String(), IntegrityMetadataSet(),
807                                 kParserInserted, example_url,
808                                 ResourceRequest::RedirectStatus::kNoRedirect,
809                                 ReportingDisposition::kSuppressReporting));
810 
811   EXPECT_TRUE(csp->AllowRequest(
812       mojom::blink::RequestContextType::OBJECT,
813       network::mojom::RequestDestination::kEmpty, not_example_url, String(),
814       IntegrityMetadataSet(), kParserInserted, not_example_url,
815       ResourceRequest::RedirectStatus::kNoRedirect,
816       ReportingDisposition::kSuppressReporting));
817 
818   SchemeRegistry::RemoveURLSchemeRegisteredAsBypassingContentSecurityPolicy(
819       "https");
820 }
821 
TEST_F(ContentSecurityPolicyTest,BlobAllowedWhenBypassingCSP)822 TEST_F(ContentSecurityPolicyTest, BlobAllowedWhenBypassingCSP) {
823   const KURL base;
824   execution_context = CreateExecutionContext();
825   execution_context->GetSecurityContext().SetSecurityOrigin(
826       secure_origin);                     // https://example.com
827   execution_context->SetURL(secure_url);  // https://example.com
828   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
829   csp->DidReceiveHeader("default-src https://example.com",
830                         ContentSecurityPolicyType::kEnforce,
831                         ContentSecurityPolicySource::kHTTP);
832 
833   const KURL example_url("blob:https://example.com/");
834   EXPECT_FALSE(csp->AllowRequest(mojom::blink::RequestContextType::OBJECT,
835                                  network::mojom::RequestDestination::kEmpty,
836                                  example_url, String(), IntegrityMetadataSet(),
837                                  kParserInserted, example_url,
838                                  ResourceRequest::RedirectStatus::kNoRedirect,
839                                  ReportingDisposition::kSuppressReporting));
840 
841   const KURL not_example_url("blob:https://not-example.com/");
842   EXPECT_FALSE(csp->AllowRequest(
843       mojom::blink::RequestContextType::OBJECT,
844       network::mojom::RequestDestination::kEmpty, not_example_url, String(),
845       IntegrityMetadataSet(), kParserInserted, not_example_url,
846       ResourceRequest::RedirectStatus::kNoRedirect,
847       ReportingDisposition::kSuppressReporting));
848 
849   // Register "https" as bypassing CSP, which should now bypass it entirely
850   SchemeRegistry::RegisterURLSchemeAsBypassingContentSecurityPolicy("https");
851 
852   EXPECT_TRUE(csp->AllowRequest(mojom::blink::RequestContextType::OBJECT,
853                                 network::mojom::RequestDestination::kEmpty,
854                                 example_url, String(), IntegrityMetadataSet(),
855                                 kParserInserted, example_url,
856                                 ResourceRequest::RedirectStatus::kNoRedirect,
857                                 ReportingDisposition::kSuppressReporting));
858 
859   EXPECT_TRUE(csp->AllowRequest(
860       mojom::blink::RequestContextType::OBJECT,
861       network::mojom::RequestDestination::kEmpty, not_example_url, String(),
862       IntegrityMetadataSet(), kParserInserted, not_example_url,
863       ResourceRequest::RedirectStatus::kNoRedirect,
864       ReportingDisposition::kSuppressReporting));
865 
866   SchemeRegistry::RemoveURLSchemeRegisteredAsBypassingContentSecurityPolicy(
867       "https");
868 }
869 
TEST_F(ContentSecurityPolicyTest,CSPBypassDisabledWhenSchemeIsPrivileged)870 TEST_F(ContentSecurityPolicyTest, CSPBypassDisabledWhenSchemeIsPrivileged) {
871   const KURL base;
872   execution_context = CreateExecutionContext();
873   execution_context->GetSecurityContext().SetSecurityOrigin(secure_origin);
874   execution_context->SetURL(BlankURL());
875   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
876   csp->DidReceiveHeader("script-src http://example.com",
877                         ContentSecurityPolicyType::kEnforce,
878                         ContentSecurityPolicySource::kHTTP);
879 
880   const KURL allowed_url("http://example.com/script.js");
881   const KURL http_url("http://not-example.com/script.js");
882   const KURL blob_url(base, "blob:http://not-example.com/uuid");
883   const KURL filesystem_url(base, "filesystem:http://not-example.com/file.js");
884 
885   // The {Requests,Blob,Filesystem}AllowedWhenBypassingCSP tests have already
886   // ensured that RegisterURLSchemeAsBypassingContentSecurityPolicy works as
887   // expected.
888   //
889   // "http" is registered as bypassing CSP, but the context's scheme ("https")
890   // is marked as a privileged scheme, so the bypass rule should be ignored.
891   SchemeRegistry::RegisterURLSchemeAsBypassingContentSecurityPolicy("http");
892   SchemeRegistry::RegisterURLSchemeAsNotAllowingJavascriptURLs("https");
893 
894   EXPECT_TRUE(csp->AllowScriptFromSource(
895       allowed_url, String(), IntegrityMetadataSet(), kNotParserInserted,
896       allowed_url, ResourceRequest::RedirectStatus::kNoRedirect,
897       ReportingDisposition::kSuppressReporting));
898   EXPECT_FALSE(csp->AllowScriptFromSource(
899       http_url, String(), IntegrityMetadataSet(), kNotParserInserted, http_url,
900       ResourceRequest::RedirectStatus::kNoRedirect,
901       ReportingDisposition::kSuppressReporting));
902   EXPECT_FALSE(csp->AllowScriptFromSource(
903       blob_url, String(), IntegrityMetadataSet(), kNotParserInserted, blob_url,
904       ResourceRequest::RedirectStatus::kNoRedirect,
905       ReportingDisposition::kSuppressReporting));
906   EXPECT_FALSE(csp->AllowScriptFromSource(
907       filesystem_url, String(), IntegrityMetadataSet(), kNotParserInserted,
908       filesystem_url, ResourceRequest::RedirectStatus::kNoRedirect,
909       ReportingDisposition::kSuppressReporting));
910 
911   SchemeRegistry::RemoveURLSchemeRegisteredAsBypassingContentSecurityPolicy(
912       "http");
913   SchemeRegistry::RemoveURLSchemeAsNotAllowingJavascriptURLs("https");
914 }
915 
916 // TODO(antoniosartori): Remove this test and the function
917 // ContentSecurityPolicy::IsValidCSPAttr when we remove the feature flag.
TEST_F(ContentSecurityPolicyTest,IsValidCSPAttrTest)918 TEST_F(ContentSecurityPolicyTest, IsValidCSPAttrTest) {
919   base::test::ScopedFeatureList feature_list;
920   feature_list.InitAndDisableFeature(network::features::kOutOfBlinkCSPEE);
921 
922   // Empty string is invalid
923   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr("", ""));
924 
925   // Policy with single directive
926   EXPECT_TRUE(
927       ContentSecurityPolicy::IsValidCSPAttr("base-uri http://example.com", ""));
928   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
929       "invalid-policy-name http://example.com", ""));
930 
931   // Policy with multiple directives
932   EXPECT_TRUE(ContentSecurityPolicy::IsValidCSPAttr(
933       "base-uri http://example.com 'self'; child-src http://example.com; "
934       "default-src http://example.com",
935       ""));
936   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
937       "default-src http://example.com; "
938       "invalid-policy-name http://example.com",
939       ""));
940 
941   // 'self', 'none'
942   EXPECT_TRUE(ContentSecurityPolicy::IsValidCSPAttr("script-src 'self'", ""));
943   EXPECT_TRUE(ContentSecurityPolicy::IsValidCSPAttr("default-src 'none'", ""));
944   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr("script-src 'slef'", ""));
945   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr("default-src 'non'", ""));
946 
947   // invalid ascii character
948   EXPECT_FALSE(
949       ContentSecurityPolicy::IsValidCSPAttr("script-src https:  \x08", ""));
950   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
951       "script-src 127.0.0.1%2F%DFisnotSorB%2F", ""));
952 
953   // paths on script-src
954   EXPECT_TRUE(
955       ContentSecurityPolicy::IsValidCSPAttr("script-src 127.0.0.1:*/", ""));
956   EXPECT_TRUE(
957       ContentSecurityPolicy::IsValidCSPAttr("script-src 127.0.0.1:*/path", ""));
958   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
959       "script-src 127.0.0.1:*/path?query=string", ""));
960   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
961       "script-src 127.0.0.1:*/path#anchor", ""));
962   EXPECT_TRUE(
963       ContentSecurityPolicy::IsValidCSPAttr("script-src 127.0.0.1:8000/", ""));
964   EXPECT_TRUE(ContentSecurityPolicy::IsValidCSPAttr(
965       "script-src 127.0.0.1:8000/path", ""));
966   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
967       "script-src 127.0.0.1:8000/path?query=string", ""));
968   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
969       "script-src 127.0.0.1:8000/path#anchor", ""));
970   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
971       "script-src 127.0.0.1:8000/thisisa;pathwithasemicolon", ""));
972 
973   // script-src invalid hosts
974   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr("script-src http:/", ""));
975   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr("script-src http://", ""));
976   EXPECT_FALSE(
977       ContentSecurityPolicy::IsValidCSPAttr("script-src http:/127.0.0.1", ""));
978   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
979       "script-src http:///127.0.0.1", ""));
980   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
981       "script-src http://127.0.0.1:/", ""));
982   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
983       "script-src https://127.?.0.1:*", ""));
984   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
985       "script-src https://127.0.0.1:", ""));
986   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
987       "script-src https://127.0.0.1:\t*   ", ""));
988 
989   // script-src host wildcards
990   EXPECT_TRUE(ContentSecurityPolicy::IsValidCSPAttr(
991       "script-src http://*.0.1:8000", ""));
992   EXPECT_TRUE(ContentSecurityPolicy::IsValidCSPAttr(
993       "script-src http://*.0.1:8000/", ""));
994   EXPECT_TRUE(
995       ContentSecurityPolicy::IsValidCSPAttr("script-src http://*.0.1:*", ""));
996   EXPECT_TRUE(
997       ContentSecurityPolicy::IsValidCSPAttr("script-src http://*.0.1:*/", ""));
998 
999   // missing semicolon
1000   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1001       "default-src 'self' script-src example.com", ""));
1002   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1003       "script-src 'self' object-src 'self' style-src *", ""));
1004 
1005   // 'none' with other sources
1006   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1007       "script-src http://127.0.0.1:8000 'none'", ""));
1008   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1009       "script-src 'none' 'none' 'none'", ""));
1010 
1011   // comma separated
1012   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1013       "script-src 'none', object-src 'none'", ""));
1014 
1015   // reporting not allowed
1016   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1017       "script-src 'none'; report-uri http://example.com/reporting", ""));
1018   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1019       "report-uri relative-path/reporting;"
1020       "base-uri http://example.com 'self'",
1021       ""));
1022 
1023   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1024       "script-src 'none'; report-to http://example.com/reporting", ""));
1025   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1026       "report-to relative-path/reporting;"
1027       "base-uri http://example.com 'self'",
1028       ""));
1029 
1030   // CRLF should not be allowed
1031   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1032       "base-uri\nhttp://example.com", ""));
1033   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1034       "base-uri http://example.com\nhttp://example2.com", ""));
1035   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1036       "base\n-uri http://example.com", ""));
1037   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1038       "\nbase-uri http://example.com", ""));
1039 
1040   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1041       "base-uri\r\nhttp://example.com", ""));
1042   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1043       "base-uri http://example.com\r\nhttp://example2.com", ""));
1044   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1045       "base\r\n-uri http://example.com", ""));
1046   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1047       "\r\nbase-uri http://example.com", ""));
1048 
1049   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1050       "base-uri\rhttp://example.com", ""));
1051   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1052       "base-uri http://example.com\rhttp://example2.com", ""));
1053   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1054       "base\r-uri http://example.com", ""));
1055   EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr(
1056       "\rbase-uri http://example.com", ""));
1057 }
1058 
TEST_F(ContentSecurityPolicyTest,TrustedTypesNoDirective)1059 TEST_F(ContentSecurityPolicyTest, TrustedTypesNoDirective) {
1060   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1061   csp->DidReceiveHeader("", ContentSecurityPolicyType::kEnforce,
1062                         ContentSecurityPolicySource::kHTTP);
1063   EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", false));
1064   EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", true));
1065 }
1066 
TEST_F(ContentSecurityPolicyTest,TrustedTypesSimpleDirective)1067 TEST_F(ContentSecurityPolicyTest, TrustedTypesSimpleDirective) {
1068   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1069   csp->DidReceiveHeader("trusted-types one two three",
1070                         ContentSecurityPolicyType::kEnforce,
1071                         ContentSecurityPolicySource::kHTTP);
1072 }
1073 
TEST_F(ContentSecurityPolicyTest,TrustedTypesWhitespace)1074 TEST_F(ContentSecurityPolicyTest, TrustedTypesWhitespace) {
1075   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1076   csp->DidReceiveHeader("trusted-types one\ntwo\rthree",
1077                         ContentSecurityPolicyType::kEnforce,
1078                         ContentSecurityPolicySource::kHTTP);
1079   EXPECT_TRUE(csp->AllowTrustedTypePolicy("one", false));
1080   EXPECT_TRUE(csp->AllowTrustedTypePolicy("two", false));
1081   EXPECT_TRUE(csp->AllowTrustedTypePolicy("three", false));
1082   EXPECT_FALSE(csp->AllowTrustedTypePolicy("four", false));
1083   EXPECT_FALSE(csp->AllowTrustedTypePolicy("one", true));
1084   EXPECT_FALSE(csp->AllowTrustedTypePolicy("four", true));
1085 }
1086 
TEST_F(ContentSecurityPolicyTest,TrustedTypesEmpty)1087 TEST_F(ContentSecurityPolicyTest, TrustedTypesEmpty) {
1088   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1089   csp->DidReceiveHeader("trusted-types", ContentSecurityPolicyType::kEnforce,
1090                         ContentSecurityPolicySource::kHTTP);
1091   EXPECT_FALSE(csp->AllowTrustedTypePolicy("somepolicy", false));
1092   EXPECT_FALSE(csp->AllowTrustedTypePolicy("somepolicy", true));
1093 }
1094 
TEST_F(ContentSecurityPolicyTest,TrustedTypesStar)1095 TEST_F(ContentSecurityPolicyTest, TrustedTypesStar) {
1096   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1097   csp->DidReceiveHeader("trusted-types *", ContentSecurityPolicyType::kEnforce,
1098                         ContentSecurityPolicySource::kHTTP);
1099   EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", false));
1100   EXPECT_FALSE(csp->AllowTrustedTypePolicy("somepolicy", true));
1101 }
1102 
TEST_F(ContentSecurityPolicyTest,TrustedTypesStarMix)1103 TEST_F(ContentSecurityPolicyTest, TrustedTypesStarMix) {
1104   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1105   csp->DidReceiveHeader("trusted-types abc * def",
1106                         ContentSecurityPolicyType::kEnforce,
1107                         ContentSecurityPolicySource::kHTTP);
1108   EXPECT_TRUE(csp->AllowTrustedTypePolicy("abc", false));
1109   EXPECT_TRUE(csp->AllowTrustedTypePolicy("def", false));
1110   EXPECT_TRUE(csp->AllowTrustedTypePolicy("ghi", false));
1111   EXPECT_FALSE(csp->AllowTrustedTypePolicy("abc", true));
1112   EXPECT_FALSE(csp->AllowTrustedTypePolicy("def", true));
1113   EXPECT_FALSE(csp->AllowTrustedTypePolicy("ghi", true));
1114 }
1115 
TEST_F(ContentSecurityPolicyTest,TrustedTypeDupe)1116 TEST_F(ContentSecurityPolicyTest, TrustedTypeDupe) {
1117   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1118   csp->DidReceiveHeader("trusted-types somepolicy 'allow-duplicates'",
1119                         ContentSecurityPolicyType::kEnforce,
1120                         ContentSecurityPolicySource::kHTTP);
1121   EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", false));
1122   EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", true));
1123 }
1124 
TEST_F(ContentSecurityPolicyTest,TrustedTypeDupeStar)1125 TEST_F(ContentSecurityPolicyTest, TrustedTypeDupeStar) {
1126   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1127   csp->DidReceiveHeader("trusted-types * 'allow-duplicates'",
1128                         ContentSecurityPolicyType::kEnforce,
1129                         ContentSecurityPolicySource::kHTTP);
1130   EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", false));
1131   EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", true));
1132 }
1133 
TEST_F(ContentSecurityPolicyTest,TrustedTypesReserved)1134 TEST_F(ContentSecurityPolicyTest, TrustedTypesReserved) {
1135   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1136   csp->DidReceiveHeader("trusted-types one \"two\" 'three'",
1137                         ContentSecurityPolicyType::kEnforce,
1138                         ContentSecurityPolicySource::kHTTP);
1139   EXPECT_TRUE(csp->AllowTrustedTypePolicy("one", false));
1140   EXPECT_TRUE(csp->AllowTrustedTypePolicy("one", false));
1141 
1142   // Quoted strings are considered 'reserved':
1143   EXPECT_FALSE(csp->AllowTrustedTypePolicy("two", false));
1144   EXPECT_FALSE(csp->AllowTrustedTypePolicy("\"two\"", false));
1145   EXPECT_FALSE(csp->AllowTrustedTypePolicy("three", false));
1146   EXPECT_FALSE(csp->AllowTrustedTypePolicy("'three'", false));
1147   EXPECT_FALSE(csp->AllowTrustedTypePolicy("two", true));
1148   EXPECT_FALSE(csp->AllowTrustedTypePolicy("\"two\"", true));
1149   EXPECT_FALSE(csp->AllowTrustedTypePolicy("three", true));
1150   EXPECT_FALSE(csp->AllowTrustedTypePolicy("'three'", true));
1151 }
1152 
TEST_F(ContentSecurityPolicyTest,TrustedTypesReportingStar)1153 TEST_F(ContentSecurityPolicyTest, TrustedTypesReportingStar) {
1154   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1155   csp->DidReceiveHeader("trusted-types *", ContentSecurityPolicyType::kReport,
1156                         ContentSecurityPolicySource::kHTTP);
1157   EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", false));
1158   EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", true));
1159 }
1160 
TEST_F(ContentSecurityPolicyTest,TrustedTypeReportingSimple)1161 TEST_F(ContentSecurityPolicyTest, TrustedTypeReportingSimple) {
1162   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1163   csp->DidReceiveHeader("trusted-types a b c",
1164                         ContentSecurityPolicyType::kReport,
1165                         ContentSecurityPolicySource::kHTTP);
1166   EXPECT_TRUE(csp->AllowTrustedTypePolicy("a", false));
1167   EXPECT_TRUE(csp->AllowTrustedTypePolicy("a", true));
1168 }
1169 
TEST_F(ContentSecurityPolicyTest,TrustedTypeEnforce)1170 TEST_F(ContentSecurityPolicyTest, TrustedTypeEnforce) {
1171   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1172   csp->DidReceiveHeader("trusted-types one\ntwo\rthree",
1173                         ContentSecurityPolicyType::kEnforce,
1174                         ContentSecurityPolicySource::kHTTP);
1175   EXPECT_FALSE(csp->IsRequireTrustedTypes());
1176   EXPECT_TRUE(csp->AllowTrustedTypeAssignmentFailure("blabla"));
1177 }
1178 
TEST_F(ContentSecurityPolicyTest,TrustedTypeReport)1179 TEST_F(ContentSecurityPolicyTest, TrustedTypeReport) {
1180   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1181   csp->DidReceiveHeader("trusted-types one\ntwo\rthree",
1182                         ContentSecurityPolicyType::kReport,
1183                         ContentSecurityPolicySource::kHTTP);
1184   EXPECT_FALSE(csp->IsRequireTrustedTypes());
1185   EXPECT_TRUE(csp->AllowTrustedTypeAssignmentFailure("blabla"));
1186 }
1187 
TEST_F(ContentSecurityPolicyTest,TrustedTypeReportAndEnforce)1188 TEST_F(ContentSecurityPolicyTest, TrustedTypeReportAndEnforce) {
1189   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1190   csp->DidReceiveHeader("trusted-types one", ContentSecurityPolicyType::kReport,
1191                         ContentSecurityPolicySource::kHTTP);
1192   csp->DidReceiveHeader("trusted-types two",
1193                         ContentSecurityPolicyType::kEnforce,
1194                         ContentSecurityPolicySource::kHTTP);
1195   EXPECT_FALSE(csp->IsRequireTrustedTypes());
1196   EXPECT_TRUE(csp->AllowTrustedTypeAssignmentFailure("blabla"));
1197 }
1198 
TEST_F(ContentSecurityPolicyTest,TrustedTypeReportAndNonTTEnforce)1199 TEST_F(ContentSecurityPolicyTest, TrustedTypeReportAndNonTTEnforce) {
1200   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1201   csp->DidReceiveHeader("trusted-types one", ContentSecurityPolicyType::kReport,
1202                         ContentSecurityPolicySource::kHTTP);
1203   csp->DidReceiveHeader("script-src none", ContentSecurityPolicyType::kEnforce,
1204                         ContentSecurityPolicySource::kHTTP);
1205   EXPECT_FALSE(csp->IsRequireTrustedTypes());
1206   EXPECT_TRUE(csp->AllowTrustedTypeAssignmentFailure("blabla"));
1207 }
1208 
TEST_F(ContentSecurityPolicyTest,RequireTrustedTypeForEnforce)1209 TEST_F(ContentSecurityPolicyTest, RequireTrustedTypeForEnforce) {
1210   execution_context->GetSecurityContext().SetRequireTrustedTypesForTesting();
1211   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1212   csp->DidReceiveHeader("require-trusted-types-for ''",
1213                         ContentSecurityPolicyType::kEnforce,
1214                         ContentSecurityPolicySource::kHTTP);
1215   EXPECT_FALSE(csp->IsRequireTrustedTypes());
1216 
1217   csp->DidReceiveHeader("require-trusted-types-for 'script'",
1218                         ContentSecurityPolicyType::kEnforce,
1219                         ContentSecurityPolicySource::kHTTP);
1220   EXPECT_TRUE(csp->IsRequireTrustedTypes());
1221 }
1222 
TEST_F(ContentSecurityPolicyTest,RequireTrustedTypeForReport)1223 TEST_F(ContentSecurityPolicyTest, RequireTrustedTypeForReport) {
1224   execution_context->GetSecurityContext().SetRequireTrustedTypesForTesting();
1225   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1226   csp->DidReceiveHeader("require-trusted-types-for 'script'",
1227                         ContentSecurityPolicyType::kReport,
1228                         ContentSecurityPolicySource::kHTTP);
1229   EXPECT_TRUE(csp->IsRequireTrustedTypes());
1230 }
1231 
TEST_F(ContentSecurityPolicyTest,DefaultPolicy)1232 TEST_F(ContentSecurityPolicyTest, DefaultPolicy) {
1233   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1234   csp->DidReceiveHeader("trusted-types *", ContentSecurityPolicyType::kEnforce,
1235                         ContentSecurityPolicySource::kHTTP);
1236   EXPECT_TRUE(csp->AllowTrustedTypePolicy("default", false));
1237   EXPECT_FALSE(csp->AllowTrustedTypePolicy("default", true));
1238 }
1239 
TEST_F(ContentSecurityPolicyTest,DirectiveNameCaseInsensitive)1240 TEST_F(ContentSecurityPolicyTest, DirectiveNameCaseInsensitive) {
1241   KURL example_url("http://example.com");
1242   KURL not_example_url("http://not-example.com");
1243 
1244   // Directive name is case insensitive.
1245   csp = MakeGarbageCollected<ContentSecurityPolicy>();
1246   csp->DidReceiveHeader("sCrIpt-sRc http://example.com",
1247                         ContentSecurityPolicyType::kEnforce,
1248                         ContentSecurityPolicySource::kHTTP);
1249   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1250 
1251   EXPECT_TRUE(csp->AllowScriptFromSource(
1252       example_url, String(), IntegrityMetadataSet(), kParserInserted,
1253       example_url, ResourceRequest::RedirectStatus::kNoRedirect));
1254   EXPECT_FALSE(csp->AllowScriptFromSource(
1255       not_example_url, String(), IntegrityMetadataSet(), kParserInserted,
1256       not_example_url, ResourceRequest::RedirectStatus::kNoRedirect));
1257 
1258   // Duplicate directive that is in a different case pattern is
1259   // correctly treated as a duplicate directive and ignored.
1260   csp = MakeGarbageCollected<ContentSecurityPolicy>();
1261   csp->DidReceiveHeader(
1262       "SCRipt-SRC http://example.com; script-src http://not-example.com;",
1263       ContentSecurityPolicyType::kEnforce, ContentSecurityPolicySource::kHTTP);
1264   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1265 
1266   EXPECT_TRUE(csp->AllowScriptFromSource(
1267       example_url, String(), IntegrityMetadataSet(), kParserInserted,
1268       example_url, ResourceRequest::RedirectStatus::kNoRedirect));
1269   EXPECT_FALSE(csp->AllowScriptFromSource(
1270       not_example_url, String(), IntegrityMetadataSet(), kParserInserted,
1271       not_example_url, ResourceRequest::RedirectStatus::kNoRedirect));
1272 }
1273 
1274 // Tests that using an empty CSP works and doesn't impose any policy
1275 // restrictions.
TEST_F(ContentSecurityPolicyTest,EmptyCSPIsNoOp)1276 TEST_F(ContentSecurityPolicyTest, EmptyCSPIsNoOp) {
1277   csp = MakeGarbageCollected<ContentSecurityPolicy>();
1278   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1279 
1280   const KURL example_url("http://example.com");
1281   auto* document = Document::CreateForTest();
1282   String source;
1283   String context_url;
1284   String nonce;
1285   OrdinalNumber ordinal_number;
1286   auto* element =
1287       MakeGarbageCollected<HTMLScriptElement>(*document, CreateElementFlags());
1288 
1289   EXPECT_TRUE(csp->Headers().IsEmpty());
1290   EXPECT_TRUE(csp->AllowInline(ContentSecurityPolicy::InlineType::kNavigation,
1291                                element, source, String() /* nonce */,
1292                                context_url, ordinal_number));
1293   EXPECT_TRUE(csp->AllowInline(
1294       ContentSecurityPolicy::InlineType::kScriptAttribute, element, source,
1295       String() /* nonce */, context_url, ordinal_number));
1296   EXPECT_TRUE(csp->AllowEval(ReportingDisposition::kReport,
1297                              ContentSecurityPolicy::kWillNotThrowException,
1298                              g_empty_string));
1299   EXPECT_TRUE(csp->AllowWasmEval(ReportingDisposition::kReport,
1300                                  ContentSecurityPolicy::kWillNotThrowException,
1301                                  g_empty_string));
1302   EXPECT_TRUE(csp->AllowPluginType("application/x-type-1",
1303                                    "application/x-type-1", example_url));
1304   EXPECT_TRUE(csp->AllowPluginType("application/x-type-1",
1305                                    "application/x-type-1", example_url,
1306                                    ReportingDisposition::kSuppressReporting));
1307 
1308   ContentSecurityPolicy::DirectiveType types_to_test[] = {
1309       ContentSecurityPolicy::DirectiveType::kBaseURI,
1310       ContentSecurityPolicy::DirectiveType::kConnectSrc,
1311       ContentSecurityPolicy::DirectiveType::kFontSrc,
1312       ContentSecurityPolicy::DirectiveType::kFormAction,
1313       ContentSecurityPolicy::DirectiveType::kFrameSrc,
1314       ContentSecurityPolicy::DirectiveType::kImgSrc,
1315       ContentSecurityPolicy::DirectiveType::kManifestSrc,
1316       ContentSecurityPolicy::DirectiveType::kMediaSrc,
1317       ContentSecurityPolicy::DirectiveType::kObjectSrc,
1318       ContentSecurityPolicy::DirectiveType::kPrefetchSrc,
1319       ContentSecurityPolicy::DirectiveType::kScriptSrcElem,
1320       ContentSecurityPolicy::DirectiveType::kStyleSrcElem,
1321       ContentSecurityPolicy::DirectiveType::kWorkerSrc};
1322   for (auto type : types_to_test) {
1323     EXPECT_TRUE(
1324         csp->AllowFromSource(type, example_url, example_url,
1325                              ResourceRequest::RedirectStatus::kNoRedirect));
1326   }
1327 
1328   EXPECT_TRUE(csp->AllowObjectFromSource(example_url));
1329   EXPECT_TRUE(csp->AllowImageFromSource(
1330       example_url, example_url, ResourceRequest::RedirectStatus::kNoRedirect));
1331   EXPECT_TRUE(csp->AllowMediaFromSource(example_url));
1332   EXPECT_TRUE(csp->AllowConnectToSource(
1333       example_url, example_url, ResourceRequest::RedirectStatus::kNoRedirect));
1334   EXPECT_TRUE(csp->AllowFormAction(example_url));
1335   EXPECT_TRUE(csp->AllowBaseURI(example_url));
1336   EXPECT_TRUE(csp->AllowWorkerContextFromSource(example_url));
1337   EXPECT_TRUE(csp->AllowScriptFromSource(
1338       example_url, nonce, IntegrityMetadataSet(), kParserInserted, example_url,
1339       ResourceRequest::RedirectStatus::kNoRedirect));
1340 
1341   EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", true));
1342   EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy", false));
1343   EXPECT_TRUE(csp->AllowInline(ContentSecurityPolicy::InlineType::kScript,
1344                                element, source, nonce, context_url,
1345                                ordinal_number));
1346   EXPECT_TRUE(csp->AllowInline(ContentSecurityPolicy::InlineType::kStyle,
1347                                element, source, nonce, context_url,
1348                                ordinal_number));
1349   EXPECT_TRUE(csp->AllowRequest(mojom::blink::RequestContextType::SCRIPT,
1350                                 network::mojom::RequestDestination::kScript,
1351                                 example_url, nonce, IntegrityMetadataSet(),
1352                                 kParserInserted, example_url,
1353                                 ResourceRequest::RedirectStatus::kNoRedirect));
1354   EXPECT_FALSE(csp->IsActive());
1355   EXPECT_FALSE(csp->IsActiveForConnections());
1356   EXPECT_TRUE(csp->FallbackUrlForPlugin().IsEmpty());
1357   EXPECT_EQ(mojom::blink::InsecureRequestPolicy::kLeaveInsecureRequestsAlone,
1358             csp->GetInsecureRequestPolicy());
1359   EXPECT_FALSE(csp->HasHeaderDeliveredPolicy());
1360   EXPECT_FALSE(csp->SupportsWasmEval());
1361   EXPECT_EQ(network::mojom::blink::WebSandboxFlags::kNone,
1362             csp->GetSandboxMask());
1363   EXPECT_FALSE(csp->HasPolicyFromSource(ContentSecurityPolicySource::kHTTP));
1364 }
1365 
TEST_F(ContentSecurityPolicyTest,OpaqueOriginBeforeBind)1366 TEST_F(ContentSecurityPolicyTest, OpaqueOriginBeforeBind) {
1367   const KURL url("https://example.test");
1368 
1369   // Security Origin of execution context might change when sandbox flags
1370   // are applied. This shouldn't change the application of the 'self'
1371   // determination.
1372   secure_origin = secure_origin->DeriveNewOpaqueOrigin();
1373   execution_context = CreateExecutionContext();
1374   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
1375   csp->DidReceiveHeader("default-src 'self';",
1376                         ContentSecurityPolicyType::kEnforce,
1377                         ContentSecurityPolicySource::kMeta);
1378   EXPECT_TRUE(csp->AllowRequest(mojom::blink::RequestContextType::SUBRESOURCE,
1379                                 network::mojom::RequestDestination::kEmpty, url,
1380                                 String(), IntegrityMetadataSet(),
1381                                 kParserInserted, url,
1382                                 ResourceRequest::RedirectStatus::kNoRedirect,
1383                                 ReportingDisposition::kSuppressReporting));
1384 }
1385 
TEST_F(ContentSecurityPolicyTest,ReasonableRestrictionMetrics)1386 TEST_F(ContentSecurityPolicyTest, ReasonableRestrictionMetrics) {
1387   struct TestCase {
1388     const char* header;
1389     bool expected_object;
1390     bool expected_base;
1391     bool expected_script;
1392   } cases[] = {{"object-src 'none'", true, false, false},
1393                {"object-src 'none'; base-uri 'none'", true, true, false},
1394                {"object-src 'none'; base-uri 'none'; script-src 'none'", true,
1395                 true, true},
1396                {"object-src 'none'; base-uri 'none'; script-src 'nonce-abc'",
1397                 true, true, true},
1398                {"object-src 'none'; base-uri 'none'; script-src 'sha256-abc'",
1399                 true, true, true},
1400                {"object-src 'none'; base-uri 'none'; script-src 'nonce-abc' "
1401                 "'strict-dynamic'",
1402                 true, true, true},
1403                {"object-src 'none'; base-uri 'none'; script-src 'sha256-abc' "
1404                 "'strict-dynamic'",
1405                 true, true, true},
1406                {"object-src 'none'; base-uri 'none'; script-src 'sha256-abc' "
1407                 "https://example.com/",
1408                 true, true, false},
1409                {"object-src 'none'; base-uri 'none'; script-src 'sha256-abc' "
1410                 "https://example.com/ 'strict-dynamic'",
1411                 true, true, true}};
1412 
1413   // Enforced
1414   for (const auto& test : cases) {
1415     SCOPED_TRACE(testing::Message()
1416                  << "[Enforce] Header: `" << test.header << "`");
1417     csp = MakeGarbageCollected<ContentSecurityPolicy>();
1418     csp->DidReceiveHeader(test.header, ContentSecurityPolicyType::kEnforce,
1419                           ContentSecurityPolicySource::kHTTP);
1420     auto dummy = std::make_unique<DummyPageHolder>();
1421     csp->BindToDelegate(
1422         dummy->GetFrame().DomWindow()->GetContentSecurityPolicyDelegate());
1423 
1424     EXPECT_EQ(test.expected_object,
1425               dummy->GetDocument().IsUseCounted(
1426                   WebFeature::kCSPWithReasonableObjectRestrictions));
1427     EXPECT_EQ(test.expected_base,
1428               dummy->GetDocument().IsUseCounted(
1429                   WebFeature::kCSPWithReasonableBaseRestrictions));
1430     EXPECT_EQ(test.expected_script,
1431               dummy->GetDocument().IsUseCounted(
1432                   WebFeature::kCSPWithReasonableScriptRestrictions));
1433     EXPECT_EQ(
1434         test.expected_object && test.expected_base && test.expected_script,
1435         dummy->GetDocument().IsUseCounted(
1436             WebFeature::kCSPWithReasonableRestrictions));
1437   }
1438 
1439   // Report-Only
1440   for (const auto& test : cases) {
1441     SCOPED_TRACE(testing::Message()
1442                  << "[ReportOnly] Header: `" << test.header << "`");
1443     csp = MakeGarbageCollected<ContentSecurityPolicy>();
1444     csp->DidReceiveHeader(test.header, ContentSecurityPolicyType::kReport,
1445                           ContentSecurityPolicySource::kHTTP);
1446     auto dummy = std::make_unique<DummyPageHolder>();
1447     csp->BindToDelegate(
1448         dummy->GetFrame().DomWindow()->GetContentSecurityPolicyDelegate());
1449 
1450     EXPECT_EQ(test.expected_object,
1451               dummy->GetDocument().IsUseCounted(
1452                   WebFeature::kCSPROWithReasonableObjectRestrictions));
1453     EXPECT_EQ(test.expected_base,
1454               dummy->GetDocument().IsUseCounted(
1455                   WebFeature::kCSPROWithReasonableBaseRestrictions));
1456     EXPECT_EQ(test.expected_script,
1457               dummy->GetDocument().IsUseCounted(
1458                   WebFeature::kCSPROWithReasonableScriptRestrictions));
1459     EXPECT_EQ(
1460         test.expected_object && test.expected_base && test.expected_script,
1461         dummy->GetDocument().IsUseCounted(
1462             WebFeature::kCSPROWithReasonableRestrictions));
1463   }
1464 }
1465 
TEST_F(ContentSecurityPolicyTest,BetterThanReasonableRestrictionMetrics)1466 TEST_F(ContentSecurityPolicyTest, BetterThanReasonableRestrictionMetrics) {
1467   struct TestCase {
1468     const char* header;
1469     bool expected;
1470   } cases[] = {
1471       {"object-src 'none'", false},
1472       {"object-src 'none'; base-uri 'none'", false},
1473       {"object-src 'none'; base-uri 'none'; script-src 'none'", true},
1474       {"object-src 'none'; base-uri 'none'; script-src 'nonce-abc'", true},
1475       {"object-src 'none'; base-uri 'none'; script-src 'sha256-abc'", true},
1476       {"object-src 'none'; base-uri 'none'; script-src 'nonce-abc' "
1477        "'strict-dynamic'",
1478        false},
1479       {"object-src 'none'; base-uri 'none'; script-src 'sha256-abc' "
1480        "'strict-dynamic'",
1481        false},
1482       {"object-src 'none'; base-uri 'none'; script-src 'sha256-abc' "
1483        "https://example.com/",
1484        false},
1485       {"object-src 'none'; base-uri 'none'; script-src 'sha256-abc' "
1486        "https://example.com/ 'strict-dynamic'",
1487        false}};
1488 
1489   // Enforced
1490   for (const auto& test : cases) {
1491     SCOPED_TRACE(testing::Message()
1492                  << "[Enforce] Header: `" << test.header << "`");
1493     csp = MakeGarbageCollected<ContentSecurityPolicy>();
1494     csp->DidReceiveHeader(test.header, ContentSecurityPolicyType::kEnforce,
1495                           ContentSecurityPolicySource::kHTTP);
1496     auto dummy = std::make_unique<DummyPageHolder>();
1497     csp->BindToDelegate(
1498         dummy->GetFrame().DomWindow()->GetContentSecurityPolicyDelegate());
1499 
1500     EXPECT_EQ(test.expected,
1501               dummy->GetDocument().IsUseCounted(
1502                   WebFeature::kCSPWithBetterThanReasonableRestrictions));
1503   }
1504 
1505   // Report-Only
1506   for (const auto& test : cases) {
1507     SCOPED_TRACE(testing::Message()
1508                  << "[ReportOnly] Header: `" << test.header << "`");
1509     csp = MakeGarbageCollected<ContentSecurityPolicy>();
1510     csp->DidReceiveHeader(test.header, ContentSecurityPolicyType::kReport,
1511                           ContentSecurityPolicySource::kHTTP);
1512     auto dummy = std::make_unique<DummyPageHolder>();
1513     csp->BindToDelegate(
1514         dummy->GetFrame().DomWindow()->GetContentSecurityPolicyDelegate());
1515 
1516     EXPECT_EQ(test.expected,
1517               dummy->GetDocument().IsUseCounted(
1518                   WebFeature::kCSPROWithBetterThanReasonableRestrictions));
1519   }
1520 }
1521 
1522 }  // namespace blink
1523