| 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 <set> | 5 #include <set> |
| 6 | 6 |
| 7 #include "content/common/content_security_policy/csp_context.h" | 7 #include "content/common/content_security_policy/csp_context.h" |
| 8 #include "content/common/content_security_policy_header.h" | 8 #include "content/common/content_security_policy_header.h" |
| 9 #include "content/common/navigation_params.h" | 9 #include "content/common/navigation_params.h" |
| 10 #include "testing/gtest/include/gtest/gtest.h" | 10 #include "testing/gtest/include/gtest/gtest.h" |
| 11 | 11 |
| 12 namespace content { | 12 namespace content { |
| 13 | 13 |
| 14 namespace { | 14 namespace { |
| 15 | 15 |
| 16 class CSPContextTest : public CSPContext { | 16 class CSPContextTest : public CSPContext { |
| 17 public: | 17 public: |
| 18 const CSPViolationParams& last_violation() { return last_violation_; } | 18 const std::vector<CSPViolationParams>& violations() { return violations_; } |
| 19 | 19 |
| 20 void AddSchemeToBypassCSP(const std::string& scheme) { | 20 void AddSchemeToBypassCSP(const std::string& scheme) { |
| 21 scheme_to_bypass_.insert(scheme); | 21 scheme_to_bypass_.insert(scheme); |
| 22 } | 22 } |
| 23 | 23 |
| 24 bool SchemeShouldBypassCSP(const base::StringPiece& scheme) override { | 24 bool SchemeShouldBypassCSP(const base::StringPiece& scheme) override { |
| 25 return scheme_to_bypass_.count(scheme.as_string()); | 25 return scheme_to_bypass_.count(scheme.as_string()); |
| 26 } | 26 } |
| 27 | 27 |
| 28 void set_sanitize_data_for_use_in_csp_violation(bool value) { | 28 void set_sanitize_data_for_use_in_csp_violation(bool value) { |
| 29 sanitize_data_for_use_in_csp_violation_ = value; | 29 sanitize_data_for_use_in_csp_violation_ = value; |
| 30 } | 30 } |
| 31 | 31 |
| 32 void SanitizeDataForUseInCspViolation( | 32 void SanitizeDataForUseInCspViolation( |
| 33 bool is_redirect, | 33 bool is_redirect, |
| 34 CSPDirective::Name directive, | 34 CSPDirective::Name directive, |
| 35 GURL* blocked_url, | 35 GURL* blocked_url, |
| 36 SourceLocation* source_location) const override { | 36 SourceLocation* source_location) const override { |
| 37 if (!sanitize_data_for_use_in_csp_violation_) | 37 if (!sanitize_data_for_use_in_csp_violation_) |
| 38 return; | 38 return; |
| 39 *blocked_url = blocked_url->GetOrigin(); | 39 *blocked_url = blocked_url->GetOrigin(); |
| 40 *source_location = | 40 *source_location = |
| 41 SourceLocation(GURL(source_location->url).GetOrigin().spec(), 0u, 0u); | 41 SourceLocation(GURL(source_location->url).GetOrigin().spec(), 0u, 0u); |
| 42 } | 42 } |
| 43 | 43 |
| 44 private: | 44 private: |
| 45 void ReportContentSecurityPolicyViolation( | 45 void ReportContentSecurityPolicyViolation( |
| 46 const CSPViolationParams& violation_params) override { | 46 const CSPViolationParams& violation_params) override { |
| 47 last_violation_ = violation_params; | 47 violations_.push_back(violation_params); |
| 48 } | 48 } |
| 49 CSPViolationParams last_violation_; | 49 std::vector<CSPViolationParams> violations_; |
| 50 std::set<std::string> scheme_to_bypass_; | 50 std::set<std::string> scheme_to_bypass_; |
| 51 bool sanitize_data_for_use_in_csp_violation_ = false; | 51 bool sanitize_data_for_use_in_csp_violation_ = false; |
| 52 }; | 52 }; |
| 53 | 53 |
| 54 // Build a new policy made of only one directive and no report endpoints. | 54 // Build a new policy made of only one directive and no report endpoints. |
| 55 ContentSecurityPolicy BuildPolicy(CSPDirective::Name directive_name, | 55 ContentSecurityPolicy BuildPolicy(CSPDirective::Name directive_name, |
| 56 std::vector<CSPSource> sources) { | 56 std::vector<CSPSource> sources) { |
| 57 return ContentSecurityPolicy( | 57 return ContentSecurityPolicy( |
| 58 ContentSecurityPolicyHeader(std::string(), // header | 58 ContentSecurityPolicyHeader(std::string(), // header |
| 59 blink::kWebContentSecurityPolicyTypeEnforce, | 59 blink::kWebContentSecurityPolicyTypeEnforce, |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 {CSPSource("", "a.com", false, url::PORT_UNSPECIFIED, false, | 114 {CSPSource("", "a.com", false, url::PORT_UNSPECIFIED, false, |
| 115 "/iframe")})); | 115 "/iframe")})); |
| 116 | 116 |
| 117 GURL blocked_url("http://a.com/login?password=1234"); | 117 GURL blocked_url("http://a.com/login?password=1234"); |
| 118 SourceLocation source_location("http://a.com/login", 10u, 20u); | 118 SourceLocation source_location("http://a.com/login", 10u, 20u); |
| 119 | 119 |
| 120 // When the |blocked_url| and |source_location| aren't sensitive information. | 120 // When the |blocked_url| and |source_location| aren't sensitive information. |
| 121 { | 121 { |
| 122 EXPECT_FALSE(context.IsAllowedByCsp(CSPDirective::FrameSrc, blocked_url, | 122 EXPECT_FALSE(context.IsAllowedByCsp(CSPDirective::FrameSrc, blocked_url, |
| 123 false, source_location)); | 123 false, source_location)); |
| 124 EXPECT_EQ(context.last_violation().blocked_url, blocked_url); | 124 ASSERT_EQ(1u, context.violations().size()); |
| 125 EXPECT_EQ(context.last_violation().source_location.url, | 125 EXPECT_EQ(context.violations()[0].blocked_url, blocked_url); |
| 126 EXPECT_EQ(context.violations()[0].source_location.url, |
| 126 "http://a.com/login"); | 127 "http://a.com/login"); |
| 127 EXPECT_EQ(context.last_violation().source_location.line_number, 10u); | 128 EXPECT_EQ(context.violations()[0].source_location.line_number, 10u); |
| 128 EXPECT_EQ(context.last_violation().source_location.column_number, 20u); | 129 EXPECT_EQ(context.violations()[0].source_location.column_number, 20u); |
| 129 EXPECT_EQ(context.last_violation().console_message, | 130 EXPECT_EQ(context.violations()[0].console_message, |
| 130 "Refused to frame 'http://a.com/login?password=1234' because it " | 131 "Refused to frame 'http://a.com/login?password=1234' because it " |
| 131 "violates the following Content Security Policy directive: " | 132 "violates the following Content Security Policy directive: " |
| 132 "\"frame-src a.com/iframe\".\n"); | 133 "\"frame-src a.com/iframe\".\n"); |
| 133 } | 134 } |
| 134 | 135 |
| 135 context.set_sanitize_data_for_use_in_csp_violation(true); | 136 context.set_sanitize_data_for_use_in_csp_violation(true); |
| 136 | 137 |
| 137 // When the |blocked_url| and |source_location| are sensitive information. | 138 // When the |blocked_url| and |source_location| are sensitive information. |
| 138 { | 139 { |
| 139 EXPECT_FALSE(context.IsAllowedByCsp(CSPDirective::FrameSrc, blocked_url, | 140 EXPECT_FALSE(context.IsAllowedByCsp(CSPDirective::FrameSrc, blocked_url, |
| 140 false, source_location)); | 141 false, source_location)); |
| 141 EXPECT_EQ(context.last_violation().blocked_url, blocked_url.GetOrigin()); | 142 ASSERT_EQ(2u, context.violations().size()); |
| 142 EXPECT_EQ(context.last_violation().source_location.url, "http://a.com/"); | 143 EXPECT_EQ(context.violations()[1].blocked_url, blocked_url.GetOrigin()); |
| 143 EXPECT_EQ(context.last_violation().source_location.line_number, 0u); | 144 EXPECT_EQ(context.violations()[1].source_location.url, "http://a.com/"); |
| 144 EXPECT_EQ(context.last_violation().source_location.column_number, 0u); | 145 EXPECT_EQ(context.violations()[1].source_location.line_number, 0u); |
| 145 EXPECT_EQ(context.last_violation().console_message, | 146 EXPECT_EQ(context.violations()[1].source_location.column_number, 0u); |
| 147 EXPECT_EQ(context.violations()[1].console_message, |
| 146 "Refused to frame 'http://a.com/' because it violates the " | 148 "Refused to frame 'http://a.com/' because it violates the " |
| 147 "following Content Security Policy directive: \"frame-src " | 149 "following Content Security Policy directive: \"frame-src " |
| 148 "a.com/iframe\".\n"); | 150 "a.com/iframe\".\n"); |
| 149 } | 151 } |
| 150 } | 152 } |
| 151 | 153 |
| 154 // When several policies are infringed, all of them must be reported. |
| 155 TEST(CSPContextTest, MultipleInfringement) { |
| 156 CSPContextTest context; |
| 157 context.SetSelf(url::Origin(GURL("http://example.com"))); |
| 158 |
| 159 CSPSource source_a("", "a.com", false, url::PORT_UNSPECIFIED, false, ""); |
| 160 CSPSource source_b("", "b.com", false, url::PORT_UNSPECIFIED, false, ""); |
| 161 CSPSource source_c("", "c.com", false, url::PORT_UNSPECIFIED, false, ""); |
| 162 |
| 163 context.AddContentSecurityPolicy( |
| 164 BuildPolicy(CSPDirective::FrameSrc, {source_a})); |
| 165 context.AddContentSecurityPolicy( |
| 166 BuildPolicy(CSPDirective::FrameSrc, {source_b})); |
| 167 context.AddContentSecurityPolicy( |
| 168 BuildPolicy(CSPDirective::FrameSrc, {source_c})); |
| 169 |
| 170 EXPECT_FALSE(context.IsAllowedByCsp( |
| 171 CSPDirective::FrameSrc, GURL("http://c.com"), false, SourceLocation())); |
| 172 ASSERT_EQ(2u, context.violations().size()); |
| 173 const char console_message_a[] = |
| 174 "Refused to frame 'http://c.com/' because it violates the following " |
| 175 "Content Security Policy directive: \"frame-src a.com\".\n"; |
| 176 const char console_message_b[] = |
| 177 "Refused to frame 'http://c.com/' because it violates the following " |
| 178 "Content Security Policy directive: \"frame-src b.com\".\n"; |
| 179 EXPECT_EQ(console_message_a, context.violations()[0].console_message); |
| 180 EXPECT_EQ(console_message_b, context.violations()[1].console_message); |
| 181 } |
| 182 |
| 152 } // namespace content | 183 } // namespace content |
| OLD | NEW |