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