| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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 "content/common/content_security_policy/csp_context.h" | 5 #include "content/common/content_security_policy/csp_context.h" |
| 6 #include "content/common/content_security_policy_header.h" | 6 #include "content/common/content_security_policy_header.h" |
| 7 #include "content/common/navigation_params.h" | 7 #include "content/common/navigation_params.h" |
| 8 #include "testing/gtest/include/gtest/gtest.h" | 8 #include "testing/gtest/include/gtest/gtest.h" |
| 9 | 9 |
| 10 namespace content { | 10 namespace content { |
| 11 | 11 |
| 12 namespace { | 12 namespace { |
| 13 class CSPContextTest : public CSPContext { | 13 class CSPContextTest : public CSPContext { |
| 14 public: | 14 public: |
| 15 CSPContextTest() : CSPContext() {} | 15 CSPContextTest() : CSPContext() {} |
| 16 | 16 |
| 17 const std::string& LastConsoleMessage() { return console_message_; } | 17 const std::vector<CSPViolationParams>& violations() { return violations_; } |
| 18 | 18 |
| 19 void AddSchemeToBypassCSP(const std::string& scheme) { | 19 void AddSchemeToBypassCSP(const std::string& scheme) { |
| 20 scheme_to_bypass_.push_back(scheme); | 20 scheme_to_bypass_.push_back(scheme); |
| 21 } | 21 } |
| 22 | 22 |
| 23 bool SchemeShouldBypassCSP(const base::StringPiece& scheme) override { | 23 bool SchemeShouldBypassCSP(const base::StringPiece& scheme) override { |
| 24 return std::find(scheme_to_bypass_.begin(), scheme_to_bypass_.end(), | 24 return std::find(scheme_to_bypass_.begin(), scheme_to_bypass_.end(), |
| 25 scheme) != scheme_to_bypass_.end(); | 25 scheme) != scheme_to_bypass_.end(); |
| 26 } | 26 } |
| 27 | 27 |
| 28 private: | 28 private: |
| 29 void ReportContentSecurityPolicyViolation( | 29 void ReportContentSecurityPolicyViolation( |
| 30 const CSPViolationParams& violation_params) override { | 30 const CSPViolationParams& violation_params) override { |
| 31 console_message_ = violation_params.console_message; | 31 violations_.push_back(violation_params); |
| 32 } | 32 } |
| 33 std::string console_message_; | 33 std::vector<CSPViolationParams> violations_; |
| 34 std::vector<std::string> scheme_to_bypass_; | 34 std::vector<std::string> scheme_to_bypass_; |
| 35 | 35 |
| 36 DISALLOW_COPY_AND_ASSIGN(CSPContextTest); | 36 DISALLOW_COPY_AND_ASSIGN(CSPContextTest); |
| 37 }; | 37 }; |
| 38 | 38 |
| 39 ContentSecurityPolicyHeader EmptyCspHeader() { | 39 ContentSecurityPolicyHeader EmptyCspHeader() { |
| 40 return ContentSecurityPolicyHeader( | 40 return ContentSecurityPolicyHeader( |
| 41 std::string(), blink::kWebContentSecurityPolicyTypeEnforce, | 41 std::string(), blink::kWebContentSecurityPolicyTypeEnforce, |
| 42 blink::kWebContentSecurityPolicySourceHTTP); | 42 blink::kWebContentSecurityPolicySourceHTTP); |
| 43 } | 43 } |
| 44 | 44 |
| 45 } // namespace | 45 } // namespace |
| 46 | 46 |
| 47 TEST(ContentSecurityPolicy, NoDirective) { | 47 TEST(ContentSecurityPolicy, NoDirective) { |
| 48 CSPContextTest context; | 48 CSPContextTest context; |
| 49 std::vector<std::string> report_end_points; // empty | 49 std::vector<std::string> report_end_points; // empty |
| 50 ContentSecurityPolicy policy(EmptyCspHeader(), std::vector<CSPDirective>(), | 50 ContentSecurityPolicy policy(EmptyCspHeader(), std::vector<CSPDirective>(), |
| 51 report_end_points); | 51 report_end_points); |
| 52 | 52 |
| 53 EXPECT_TRUE(ContentSecurityPolicy::Allow(policy, CSPDirective::FormAction, | 53 EXPECT_TRUE(ContentSecurityPolicy::Allow(policy, CSPDirective::FormAction, |
| 54 GURL("http://www.example.com"), | 54 GURL("http://www.example.com"), |
| 55 false, &context, SourceLocation())); | 55 false, &context, SourceLocation())); |
| 56 EXPECT_EQ("", context.LastConsoleMessage()); | 56 ASSERT_EQ(0u, context.violations().size()); |
| 57 } | 57 } |
| 58 | 58 |
| 59 TEST(ContentSecurityPolicy, ReportViolation) { | 59 TEST(ContentSecurityPolicy, ReportViolation) { |
| 60 CSPContextTest context; | 60 CSPContextTest context; |
| 61 | 61 |
| 62 // source = "www.example.com" | 62 // source = "www.example.com" |
| 63 CSPSource source("", "www.example.com", false, url::PORT_UNSPECIFIED, false, | 63 CSPSource source("", "www.example.com", false, url::PORT_UNSPECIFIED, false, |
| 64 ""); | 64 ""); |
| 65 CSPSourceList source_list(false, false, {source}); | 65 CSPSourceList source_list(false, false, {source}); |
| 66 CSPDirective directive(CSPDirective::FormAction, source_list); | 66 CSPDirective directive(CSPDirective::FormAction, source_list); |
| 67 std::vector<std::string> report_end_points; // empty | 67 std::vector<std::string> report_end_points; // empty |
| 68 ContentSecurityPolicy policy(EmptyCspHeader(), {directive}, | 68 ContentSecurityPolicy policy(EmptyCspHeader(), {directive}, |
| 69 report_end_points); | 69 report_end_points); |
| 70 | 70 |
| 71 EXPECT_FALSE(ContentSecurityPolicy::Allow(policy, CSPDirective::FormAction, | 71 EXPECT_FALSE(ContentSecurityPolicy::Allow(policy, CSPDirective::FormAction, |
| 72 GURL("http://www.not-example.com"), | 72 GURL("http://www.not-example.com"), |
| 73 false, &context, SourceLocation())); | 73 false, &context, SourceLocation())); |
| 74 | 74 |
| 75 ASSERT_EQ(1u, context.violations().size()); |
| 75 const char console_message[] = | 76 const char console_message[] = |
| 76 "Refused to send form data to 'http://www.not-example.com/' because it " | 77 "Refused to send form data to 'http://www.not-example.com/' because it " |
| 77 "violates the following Content Security Policy directive: \"form-action " | 78 "violates the following Content Security Policy directive: \"form-action " |
| 78 "www.example.com\".\n"; | 79 "www.example.com\".\n"; |
| 79 EXPECT_EQ(console_message, context.LastConsoleMessage()); | 80 EXPECT_EQ(console_message, context.violations()[0].console_message); |
| 80 } | 81 } |
| 81 | 82 |
| 82 TEST(ContentSecurityPolicy, DirectiveFallback) { | 83 TEST(ContentSecurityPolicy, DirectiveFallback) { |
| 83 CSPSource source_a("http", "a.com", false, url::PORT_UNSPECIFIED, false, ""); | 84 CSPSource source_a("http", "a.com", false, url::PORT_UNSPECIFIED, false, ""); |
| 84 CSPSource source_b("http", "b.com", false, url::PORT_UNSPECIFIED, false, ""); | 85 CSPSource source_b("http", "b.com", false, url::PORT_UNSPECIFIED, false, ""); |
| 85 CSPSourceList source_list_a(false, false, {source_a}); | 86 CSPSourceList source_list_a(false, false, {source_a}); |
| 86 CSPSourceList source_list_b(false, false, {source_b}); | 87 CSPSourceList source_list_b(false, false, {source_b}); |
| 87 | 88 |
| 88 std::vector<std::string> report_end_points; // Empty. | 89 std::vector<std::string> report_end_points; // Empty. |
| 89 | 90 |
| 90 { | 91 { |
| 91 CSPContextTest context; | 92 CSPContextTest context; |
| 92 ContentSecurityPolicy policy( | 93 ContentSecurityPolicy policy( |
| 93 EmptyCspHeader(), | 94 EmptyCspHeader(), |
| 94 {CSPDirective(CSPDirective::DefaultSrc, source_list_a)}, | 95 {CSPDirective(CSPDirective::DefaultSrc, source_list_a)}, |
| 95 report_end_points); | 96 report_end_points); |
| 96 EXPECT_FALSE(ContentSecurityPolicy::Allow(policy, CSPDirective::FrameSrc, | 97 EXPECT_FALSE(ContentSecurityPolicy::Allow(policy, CSPDirective::FrameSrc, |
| 97 GURL("http://b.com"), false, | 98 GURL("http://b.com"), false, |
| 98 &context, SourceLocation())); | 99 &context, SourceLocation())); |
| 100 ASSERT_EQ(1u, context.violations().size()); |
| 99 const char console_message[] = | 101 const char console_message[] = |
| 100 "Refused to frame 'http://b.com/' because it violates " | 102 "Refused to frame 'http://b.com/' because it violates " |
| 101 "the following Content Security Policy directive: \"default-src " | 103 "the following Content Security Policy directive: \"default-src " |
| 102 "http://a.com\". Note that 'frame-src' was not explicitly " | 104 "http://a.com\". Note that 'frame-src' was not explicitly " |
| 103 "set, so 'default-src' is used as a fallback.\n"; | 105 "set, so 'default-src' is used as a fallback.\n"; |
| 104 EXPECT_EQ(console_message, context.LastConsoleMessage()); | 106 EXPECT_EQ(console_message, context.violations()[0].console_message); |
| 105 EXPECT_TRUE(ContentSecurityPolicy::Allow(policy, CSPDirective::FrameSrc, | 107 EXPECT_TRUE(ContentSecurityPolicy::Allow(policy, CSPDirective::FrameSrc, |
| 106 GURL("http://a.com"), false, | 108 GURL("http://a.com"), false, |
| 107 &context, SourceLocation())); | 109 &context, SourceLocation())); |
| 108 } | 110 } |
| 109 { | 111 { |
| 110 CSPContextTest context; | 112 CSPContextTest context; |
| 111 ContentSecurityPolicy policy( | 113 ContentSecurityPolicy policy( |
| 112 EmptyCspHeader(), {CSPDirective(CSPDirective::ChildSrc, source_list_a)}, | 114 EmptyCspHeader(), {CSPDirective(CSPDirective::ChildSrc, source_list_a)}, |
| 113 report_end_points); | 115 report_end_points); |
| 114 EXPECT_FALSE(ContentSecurityPolicy::Allow(policy, CSPDirective::FrameSrc, | 116 EXPECT_FALSE(ContentSecurityPolicy::Allow(policy, CSPDirective::FrameSrc, |
| 115 GURL("http://b.com"), false, | 117 GURL("http://b.com"), false, |
| 116 &context, SourceLocation())); | 118 &context, SourceLocation())); |
| 119 ASSERT_EQ(1u, context.violations().size()); |
| 117 const char console_message[] = | 120 const char console_message[] = |
| 118 "Refused to frame 'http://b.com/' because it violates " | 121 "Refused to frame 'http://b.com/' because it violates " |
| 119 "the following Content Security Policy directive: \"child-src " | 122 "the following Content Security Policy directive: \"child-src " |
| 120 "http://a.com\". Note that 'frame-src' was not explicitly " | 123 "http://a.com\". Note that 'frame-src' was not explicitly " |
| 121 "set, so 'child-src' is used as a fallback.\n"; | 124 "set, so 'child-src' is used as a fallback.\n"; |
| 122 EXPECT_EQ(console_message, context.LastConsoleMessage()); | 125 EXPECT_EQ(console_message, context.violations()[0].console_message); |
| 123 EXPECT_TRUE(ContentSecurityPolicy::Allow(policy, CSPDirective::FrameSrc, | 126 EXPECT_TRUE(ContentSecurityPolicy::Allow(policy, CSPDirective::FrameSrc, |
| 124 GURL("http://a.com"), false, | 127 GURL("http://a.com"), false, |
| 125 &context, SourceLocation())); | 128 &context, SourceLocation())); |
| 126 } | 129 } |
| 127 { | 130 { |
| 128 CSPContextTest context; | 131 CSPContextTest context; |
| 129 CSPSourceList source_list(false, false, {source_a, source_b}); | 132 CSPSourceList source_list(false, false, {source_a, source_b}); |
| 130 ContentSecurityPolicy policy( | 133 ContentSecurityPolicy policy( |
| 131 EmptyCspHeader(), | 134 EmptyCspHeader(), |
| 132 {CSPDirective(CSPDirective::FrameSrc, {source_list_a}), | 135 {CSPDirective(CSPDirective::FrameSrc, {source_list_a}), |
| 133 CSPDirective(CSPDirective::ChildSrc, {source_list_b})}, | 136 CSPDirective(CSPDirective::ChildSrc, {source_list_b})}, |
| 134 report_end_points); | 137 report_end_points); |
| 135 EXPECT_TRUE(ContentSecurityPolicy::Allow(policy, CSPDirective::FrameSrc, | 138 EXPECT_TRUE(ContentSecurityPolicy::Allow(policy, CSPDirective::FrameSrc, |
| 136 GURL("http://a.com"), false, | 139 GURL("http://a.com"), false, |
| 137 &context, SourceLocation())); | 140 &context, SourceLocation())); |
| 138 EXPECT_FALSE(ContentSecurityPolicy::Allow(policy, CSPDirective::FrameSrc, | 141 EXPECT_FALSE(ContentSecurityPolicy::Allow(policy, CSPDirective::FrameSrc, |
| 139 GURL("http://b.com"), false, | 142 GURL("http://b.com"), false, |
| 140 &context, SourceLocation())); | 143 &context, SourceLocation())); |
| 144 ASSERT_EQ(1u, context.violations().size()); |
| 141 const char console_message[] = | 145 const char console_message[] = |
| 142 "Refused to frame 'http://b.com/' because it violates " | 146 "Refused to frame 'http://b.com/' because it violates " |
| 143 "the following Content Security Policy directive: \"frame-src " | 147 "the following Content Security Policy directive: \"frame-src " |
| 144 "http://a.com\".\n"; | 148 "http://a.com\".\n"; |
| 145 EXPECT_EQ(console_message, context.LastConsoleMessage()); | 149 EXPECT_EQ(console_message, context.violations()[0].console_message); |
| 146 } | 150 } |
| 147 } | 151 } |
| 148 | 152 |
| 149 TEST(ContentSecurityPolicy, RequestsAllowedWhenBypassingCSP) { | 153 TEST(ContentSecurityPolicy, RequestsAllowedWhenBypassingCSP) { |
| 150 CSPContextTest context; | 154 CSPContextTest context; |
| 151 std::vector<std::string> report_end_points; // empty | 155 std::vector<std::string> report_end_points; // empty |
| 152 CSPSource source("https", "example.com", false, url::PORT_UNSPECIFIED, false, | 156 CSPSource source("https", "example.com", false, url::PORT_UNSPECIFIED, false, |
| 153 ""); | 157 ""); |
| 154 CSPSourceList source_list(false, false, {source}); | 158 CSPSourceList source_list(false, false, {source}); |
| 155 ContentSecurityPolicy policy( | 159 ContentSecurityPolicy policy( |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 | 232 |
| 229 EXPECT_TRUE(ContentSecurityPolicy::Allow(policy, CSPDirective::FrameSrc, | 233 EXPECT_TRUE(ContentSecurityPolicy::Allow(policy, CSPDirective::FrameSrc, |
| 230 GURL("blob:https://example.com/"), | 234 GURL("blob:https://example.com/"), |
| 231 false, &context, SourceLocation())); | 235 false, &context, SourceLocation())); |
| 232 EXPECT_TRUE(ContentSecurityPolicy::Allow( | 236 EXPECT_TRUE(ContentSecurityPolicy::Allow( |
| 233 policy, CSPDirective::FrameSrc, GURL("blob:https://not-example.com/"), | 237 policy, CSPDirective::FrameSrc, GURL("blob:https://not-example.com/"), |
| 234 false, &context, SourceLocation())); | 238 false, &context, SourceLocation())); |
| 235 } | 239 } |
| 236 | 240 |
| 237 } // namespace content | 241 } // namespace content |
| OLD | NEW |