OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/frame/csp/CSPDirectiveList.h" | 5 #include "core/frame/csp/CSPDirectiveList.h" |
6 | 6 |
7 #include "core/frame/csp/ContentSecurityPolicy.h" | 7 #include "core/frame/csp/ContentSecurityPolicy.h" |
8 #include "core/frame/csp/SourceListDirective.h" | 8 #include "core/frame/csp/SourceListDirective.h" |
9 #include "platform/network/ContentSecurityPolicyParsers.h" | 9 #include "platform/network/ContentSecurityPolicyParsers.h" |
10 #include "platform/network/ResourceRequest.h" | 10 #include "platform/network/ResourceRequest.h" |
(...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
428 KURL resource = KURL(KURL(), "https://example.test/worker.js"); | 428 KURL resource = KURL(KURL(), "https://example.test/worker.js"); |
429 Member<CSPDirectiveList> directiveList = | 429 Member<CSPDirectiveList> directiveList = |
430 createList(test.list, ContentSecurityPolicyHeaderTypeEnforce); | 430 createList(test.list, ContentSecurityPolicyHeaderTypeEnforce); |
431 EXPECT_EQ(test.allowed, | 431 EXPECT_EQ(test.allowed, |
432 directiveList->allowWorkerFromSource( | 432 directiveList->allowWorkerFromSource( |
433 resource, ResourceRequest::RedirectStatus::NoRedirect, | 433 resource, ResourceRequest::RedirectStatus::NoRedirect, |
434 ContentSecurityPolicy::SuppressReport)); | 434 ContentSecurityPolicy::SuppressReport)); |
435 } | 435 } |
436 } | 436 } |
437 | 437 |
| 438 TEST_F(CSPDirectiveListTest, SubsumesBasedOnCSPSourcesOnly) { |
| 439 CSPDirectiveList* A = createList( |
| 440 "script-src http://*.one.com; img-src https://one.com " |
| 441 "http://two.com/imgs/", |
| 442 ContentSecurityPolicyHeaderTypeReport); |
| 443 |
| 444 struct TestCase { |
| 445 const std::vector<const char*> policies; |
| 446 bool expected; |
| 447 bool expectedFirstPolicyOpposite; |
| 448 } cases[] = { |
| 449 // `listB`, which is not as restrictive as `A`, is not subsumed. |
| 450 {{""}, false, true}, |
| 451 {{"script-src http://example.com"}, false, false}, |
| 452 {{"img-src http://example.com"}, false, false}, |
| 453 {{"script-src http://*.one.com"}, false, true}, |
| 454 {{"img-src https://one.com http://two.com/imgs/"}, false, true}, |
| 455 {{"default-src http://example.com"}, false, false}, |
| 456 {{"default-src https://one.com http://two.com/imgs/"}, false, false}, |
| 457 {{"default-src http://one.com"}, false, false}, |
| 458 {{"script-src http://*.one.com; img-src http://two.com/"}, false, false}, |
| 459 {{"script-src http://*.one.com", "img-src http://one.com"}, false, true}, |
| 460 {{"script-src http://*.one.com", "script-src https://two.com"}, |
| 461 false, |
| 462 true}, |
| 463 {{"script-src http://*.random.com", "script-src https://random.com"}, |
| 464 false, |
| 465 false}, |
| 466 {{"script-src http://one.com", "script-src https://random.com"}, |
| 467 false, |
| 468 false}, |
| 469 {{"script-src http://*.random.com; default-src http://one.com " |
| 470 "http://two.com/imgs/", |
| 471 "default-src https://random.com"}, |
| 472 false, |
| 473 false}, |
| 474 // `listB`, which is as restrictive as `A`, is subsumed. |
| 475 {{"default-src https://one.com"}, true, false}, |
| 476 {{"default-src http://random.com", |
| 477 "default-src https://non-random.com:*"}, |
| 478 true, |
| 479 false}, |
| 480 {{"script-src http://*.one.com; img-src https://one.com"}, true, false}, |
| 481 {{"script-src http://*.one.com; img-src https://one.com " |
| 482 "http://two.com/imgs/"}, |
| 483 true, |
| 484 true}, |
| 485 {{"script-src http://*.one.com", |
| 486 "img-src https://one.com http://two.com/imgs/"}, |
| 487 true, |
| 488 true}, |
| 489 {{"script-src http://*.random.com; default-src https://one.com " |
| 490 "http://two.com/imgs/", |
| 491 "default-src https://else.com"}, |
| 492 true, |
| 493 false}, |
| 494 {{"script-src http://*.random.com; default-src https://one.com " |
| 495 "http://two.com/imgs/", |
| 496 "default-src https://one.com"}, |
| 497 true, |
| 498 false}, |
| 499 }; |
| 500 |
| 501 CSPDirectiveList* emptyA = |
| 502 createList("", ContentSecurityPolicyHeaderTypeReport); |
| 503 |
| 504 for (const auto& test : cases) { |
| 505 HeapVector<Member<CSPDirectiveList>> listB; |
| 506 for (const auto& policy : test.policies) { |
| 507 listB.append(createList(policy, ContentSecurityPolicyHeaderTypeReport)); |
| 508 } |
| 509 |
| 510 EXPECT_EQ(test.expected, A->subsumes(listB)); |
| 511 // Empty CSPDirective subsumes any list. |
| 512 EXPECT_TRUE(emptyA->subsumes(listB)); |
| 513 // Check if first policy of `listB` subsumes `A`. |
| 514 EXPECT_EQ(test.expectedFirstPolicyOpposite, |
| 515 listB[0]->subsumes(HeapVector<Member<CSPDirectiveList>>(1, A))); |
| 516 } |
| 517 } |
| 518 |
| 519 TEST_F(CSPDirectiveListTest, GetSourceVector) { |
| 520 const std::vector<const char*> policies = { |
| 521 // Policy 1 |
| 522 "default-src https://default-src.com", |
| 523 // Policy 2 |
| 524 "child-src http://child-src.com", |
| 525 // Policy 3 |
| 526 "child-src http://child-src.com; default-src https://default-src.com", |
| 527 // Policy 4 |
| 528 "base-uri http://base-uri.com", |
| 529 // Policy 5 |
| 530 "frame-src http://frame-src.com"}; |
| 531 |
| 532 // Check expectations on the initial set-up. |
| 533 HeapVector<Member<CSPDirectiveList>> policyVector; |
| 534 for (const auto& policy : policies) { |
| 535 policyVector.append( |
| 536 createList(policy, ContentSecurityPolicyHeaderTypeReport)); |
| 537 } |
| 538 HeapVector<Member<SourceListDirective>> result = |
| 539 CSPDirectiveList::getSourceVector(ContentSecurityPolicy::DefaultSrc, |
| 540 policyVector); |
| 541 EXPECT_EQ(result.size(), 2u); |
| 542 result = CSPDirectiveList::getSourceVector(ContentSecurityPolicy::ChildSrc, |
| 543 policyVector); |
| 544 EXPECT_EQ(result.size(), 3u); |
| 545 result = CSPDirectiveList::getSourceVector(ContentSecurityPolicy::BaseURI, |
| 546 policyVector); |
| 547 EXPECT_EQ(result.size(), 1u); |
| 548 result = CSPDirectiveList::getSourceVector(ContentSecurityPolicy::FrameSrc, |
| 549 policyVector); |
| 550 EXPECT_EQ(result.size(), 4u); |
| 551 |
| 552 enum DefaultBehaviour { Default, NoDefault, ChildAndDefault }; |
| 553 |
| 554 struct TestCase { |
| 555 const char* directive; |
| 556 const DefaultBehaviour type; |
| 557 size_t expectedTotal; |
| 558 int expectedCurrent; |
| 559 int expectedDefaultSrc; |
| 560 int expectedChildSrc; |
| 561 } cases[] = { |
| 562 // Directives with default directive. |
| 563 {ContentSecurityPolicy::ChildSrc, Default, 4u, 3, 1, 3}, |
| 564 {ContentSecurityPolicy::ConnectSrc, Default, 3u, 1, 2, 0}, |
| 565 {ContentSecurityPolicy::FontSrc, Default, 3u, 1, 2, 0}, |
| 566 {ContentSecurityPolicy::ImgSrc, Default, 3u, 1, 2, 0}, |
| 567 {ContentSecurityPolicy::ManifestSrc, Default, 3u, 1, 2, 0}, |
| 568 {ContentSecurityPolicy::MediaSrc, Default, 3u, 1, 2, 0}, |
| 569 {ContentSecurityPolicy::ObjectSrc, Default, 3u, 1, 2, 0}, |
| 570 {ContentSecurityPolicy::ScriptSrc, Default, 3u, 1, 2, 0}, |
| 571 {ContentSecurityPolicy::StyleSrc, Default, 3u, 1, 2, 0}, |
| 572 // Directives with no default directive. |
| 573 {ContentSecurityPolicy::BaseURI, NoDefault, 2u, 2, 0, 0}, |
| 574 {ContentSecurityPolicy::FrameAncestors, NoDefault, 1u, 1, 0, 0}, |
| 575 {ContentSecurityPolicy::FormAction, NoDefault, 1u, 1, 0, 0}, |
| 576 // Directive with multiple default directives. |
| 577 {ContentSecurityPolicy::FrameSrc, ChildAndDefault, 5u, 2, 1, 2}, |
| 578 }; |
| 579 |
| 580 for (const auto& test : cases) { |
| 581 // Initial set-up. |
| 582 HeapVector<Member<CSPDirectiveList>> policyVector; |
| 583 for (const auto& policy : policies) { |
| 584 policyVector.append( |
| 585 createList(policy, ContentSecurityPolicyHeaderTypeReport)); |
| 586 } |
| 587 // Append current test's policy. |
| 588 std::stringstream currentDirective; |
| 589 currentDirective << test.directive << " http://" << test.directive |
| 590 << ".com;"; |
| 591 policyVector.append(createList(currentDirective.str().c_str(), |
| 592 ContentSecurityPolicyHeaderTypeReport)); |
| 593 |
| 594 HeapVector<Member<SourceListDirective>> result = |
| 595 CSPDirectiveList::getSourceVector(test.directive, policyVector); |
| 596 |
| 597 EXPECT_EQ(result.size(), test.expectedTotal); |
| 598 |
| 599 int actualCurrent = 0, actualDefault = 0, actualChild = 0; |
| 600 for (const auto& srcList : result) { |
| 601 HeapVector<Member<CSPSource>> sources = srcList->m_list; |
| 602 for (const auto& source : sources) { |
| 603 if (source->m_host.startsWith(test.directive)) |
| 604 actualCurrent += 1; |
| 605 else if (source->m_host == "default-src.com") |
| 606 actualDefault += 1; |
| 607 |
| 608 if (source->m_host == "child-src.com") |
| 609 actualChild += 1; |
| 610 } |
| 611 } |
| 612 |
| 613 EXPECT_EQ(actualDefault, test.expectedDefaultSrc); |
| 614 EXPECT_EQ(actualCurrent, test.expectedCurrent); |
| 615 EXPECT_EQ(actualChild, test.expectedChildSrc); |
| 616 |
| 617 // If another default-src is added that should only impact Fetch Directives |
| 618 policyVector.append(createList("default-src https://default-src.com;", |
| 619 ContentSecurityPolicyHeaderTypeReport)); |
| 620 size_t udpatedTotal = |
| 621 test.type != NoDefault ? test.expectedTotal + 1 : test.expectedTotal; |
| 622 EXPECT_EQ( |
| 623 CSPDirectiveList::getSourceVector(test.directive, policyVector).size(), |
| 624 udpatedTotal); |
| 625 size_t expectedChildSrc = |
| 626 test.directive == ContentSecurityPolicy::ChildSrc ? 5u : 4u; |
| 627 EXPECT_EQ(CSPDirectiveList::getSourceVector(ContentSecurityPolicy::ChildSrc, |
| 628 policyVector) |
| 629 .size(), |
| 630 expectedChildSrc); |
| 631 |
| 632 // If another child-src is added that should only impact frame-src and |
| 633 // child-src |
| 634 policyVector.append(createList("child-src http://child-src.com;", |
| 635 ContentSecurityPolicyHeaderTypeReport)); |
| 636 udpatedTotal = test.type == ChildAndDefault || |
| 637 test.directive == ContentSecurityPolicy::ChildSrc |
| 638 ? udpatedTotal + 1 |
| 639 : udpatedTotal; |
| 640 EXPECT_EQ( |
| 641 CSPDirectiveList::getSourceVector(test.directive, policyVector).size(), |
| 642 udpatedTotal); |
| 643 expectedChildSrc = expectedChildSrc + 1u; |
| 644 EXPECT_EQ(CSPDirectiveList::getSourceVector(ContentSecurityPolicy::ChildSrc, |
| 645 policyVector) |
| 646 .size(), |
| 647 expectedChildSrc); |
| 648 |
| 649 // If we add sandbox, nothing should change since it is currenly not |
| 650 // considered. |
| 651 policyVector.append(createList("sandbox http://sandbox.com;", |
| 652 ContentSecurityPolicyHeaderTypeReport)); |
| 653 EXPECT_EQ( |
| 654 CSPDirectiveList::getSourceVector(test.directive, policyVector).size(), |
| 655 udpatedTotal); |
| 656 EXPECT_EQ(CSPDirectiveList::getSourceVector(ContentSecurityPolicy::ChildSrc, |
| 657 policyVector) |
| 658 .size(), |
| 659 expectedChildSrc); |
| 660 } |
| 661 } |
| 662 |
438 } // namespace blink | 663 } // namespace blink |
OLD | NEW |