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/SubresourceIntegrity.h" |
7 #include "core/frame/csp/ContentSecurityPolicy.h" | 8 #include "core/frame/csp/ContentSecurityPolicy.h" |
8 #include "core/frame/csp/SourceListDirective.h" | 9 #include "core/frame/csp/SourceListDirective.h" |
9 #include "platform/loader/fetch/ResourceRequest.h" | 10 #include "platform/loader/fetch/ResourceRequest.h" |
10 #include "platform/network/ContentSecurityPolicyParsers.h" | 11 #include "platform/network/ContentSecurityPolicyParsers.h" |
11 #include "testing/gtest/include/gtest/gtest.h" | 12 #include "testing/gtest/include/gtest/gtest.h" |
12 #include "wtf/text/StringOperators.h" | 13 #include "wtf/text/StringOperators.h" |
13 #include "wtf/text/WTFString.h" | 14 #include "wtf/text/WTFString.h" |
14 | 15 |
15 namespace blink { | 16 namespace blink { |
16 | 17 |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 for (const auto& test : cases) { | 159 for (const auto& test : cases) { |
159 SCOPED_TRACE(testing::Message() << "List: `" << test.list << "`, URL: `" | 160 SCOPED_TRACE(testing::Message() << "List: `" << test.list << "`, URL: `" |
160 << test.url << "`"); | 161 << test.url << "`"); |
161 KURL scriptSrc = KURL(KURL(), test.url); | 162 KURL scriptSrc = KURL(KURL(), test.url); |
162 | 163 |
163 // Report-only | 164 // Report-only |
164 Member<CSPDirectiveList> directiveList = | 165 Member<CSPDirectiveList> directiveList = |
165 createList(test.list, ContentSecurityPolicyHeaderTypeReport); | 166 createList(test.list, ContentSecurityPolicyHeaderTypeReport); |
166 EXPECT_EQ(test.expected, | 167 EXPECT_EQ(test.expected, |
167 directiveList->allowScriptFromSource( | 168 directiveList->allowScriptFromSource( |
168 scriptSrc, String(), ParserInserted, | 169 scriptSrc, String(), IntegrityMetadataSet(), ParserInserted, |
169 ResourceRequest::RedirectStatus::NoRedirect, | 170 ResourceRequest::RedirectStatus::NoRedirect, |
170 SecurityViolationReportingPolicy::SuppressReporting)); | 171 SecurityViolationReportingPolicy::SuppressReporting)); |
171 | 172 |
172 // Enforce | 173 // Enforce |
173 directiveList = | 174 directiveList = |
174 createList(test.list, ContentSecurityPolicyHeaderTypeEnforce); | 175 createList(test.list, ContentSecurityPolicyHeaderTypeEnforce); |
175 EXPECT_EQ(test.expected, | 176 EXPECT_EQ(test.expected, |
176 directiveList->allowScriptFromSource( | 177 directiveList->allowScriptFromSource( |
177 scriptSrc, String(), ParserInserted, | 178 scriptSrc, String(), IntegrityMetadataSet(), ParserInserted, |
178 ResourceRequest::RedirectStatus::NoRedirect, | 179 ResourceRequest::RedirectStatus::NoRedirect, |
179 SecurityViolationReportingPolicy::SuppressReporting)); | 180 SecurityViolationReportingPolicy::SuppressReporting)); |
180 } | 181 } |
181 } | 182 } |
182 | 183 |
183 TEST_F(CSPDirectiveListTest, AllowFromSourceWithNonce) { | 184 TEST_F(CSPDirectiveListTest, AllowFromSourceWithNonce) { |
184 struct TestCase { | 185 struct TestCase { |
185 const char* list; | 186 const char* list; |
186 const char* url; | 187 const char* url; |
187 const char* nonce; | 188 const char* nonce; |
(...skipping 27 matching lines...) Expand all Loading... |
215 SCOPED_TRACE(testing::Message() << "List: `" << test.list << "`, URL: `" | 216 SCOPED_TRACE(testing::Message() << "List: `" << test.list << "`, URL: `" |
216 << test.url << "`"); | 217 << test.url << "`"); |
217 KURL resource = KURL(KURL(), test.url); | 218 KURL resource = KURL(KURL(), test.url); |
218 | 219 |
219 // Report-only 'script-src' | 220 // Report-only 'script-src' |
220 Member<CSPDirectiveList> directiveList = | 221 Member<CSPDirectiveList> directiveList = |
221 createList(String("script-src ") + test.list, | 222 createList(String("script-src ") + test.list, |
222 ContentSecurityPolicyHeaderTypeReport); | 223 ContentSecurityPolicyHeaderTypeReport); |
223 EXPECT_EQ(test.expected, | 224 EXPECT_EQ(test.expected, |
224 directiveList->allowScriptFromSource( | 225 directiveList->allowScriptFromSource( |
225 resource, String(test.nonce), ParserInserted, | 226 resource, String(test.nonce), IntegrityMetadataSet(), |
226 ResourceRequest::RedirectStatus::NoRedirect, | 227 ParserInserted, ResourceRequest::RedirectStatus::NoRedirect, |
227 SecurityViolationReportingPolicy::SuppressReporting)); | 228 SecurityViolationReportingPolicy::SuppressReporting)); |
228 | 229 |
229 // Enforce 'script-src' | 230 // Enforce 'script-src' |
230 directiveList = createList(String("script-src ") + test.list, | 231 directiveList = createList(String("script-src ") + test.list, |
231 ContentSecurityPolicyHeaderTypeEnforce); | 232 ContentSecurityPolicyHeaderTypeEnforce); |
232 EXPECT_EQ(test.expected, | 233 EXPECT_EQ(test.expected, |
233 directiveList->allowScriptFromSource( | 234 directiveList->allowScriptFromSource( |
234 resource, String(test.nonce), ParserInserted, | 235 resource, String(test.nonce), IntegrityMetadataSet(), |
235 ResourceRequest::RedirectStatus::NoRedirect, | 236 ParserInserted, ResourceRequest::RedirectStatus::NoRedirect, |
236 SecurityViolationReportingPolicy::SuppressReporting)); | 237 SecurityViolationReportingPolicy::SuppressReporting)); |
237 | 238 |
238 // Report-only 'style-src' | 239 // Report-only 'style-src' |
239 directiveList = createList(String("style-src ") + test.list, | 240 directiveList = createList(String("style-src ") + test.list, |
240 ContentSecurityPolicyHeaderTypeReport); | 241 ContentSecurityPolicyHeaderTypeReport); |
241 EXPECT_EQ(test.expected, | 242 EXPECT_EQ(test.expected, |
242 directiveList->allowStyleFromSource( | 243 directiveList->allowStyleFromSource( |
243 resource, String(test.nonce), | 244 resource, String(test.nonce), |
244 ResourceRequest::RedirectStatus::NoRedirect, | 245 ResourceRequest::RedirectStatus::NoRedirect, |
245 SecurityViolationReportingPolicy::SuppressReporting)); | 246 SecurityViolationReportingPolicy::SuppressReporting)); |
246 | 247 |
247 // Enforce 'style-src' | 248 // Enforce 'style-src' |
248 directiveList = createList(String("style-src ") + test.list, | 249 directiveList = createList(String("style-src ") + test.list, |
249 ContentSecurityPolicyHeaderTypeEnforce); | 250 ContentSecurityPolicyHeaderTypeEnforce); |
250 EXPECT_EQ(test.expected, | 251 EXPECT_EQ(test.expected, |
251 directiveList->allowStyleFromSource( | 252 directiveList->allowStyleFromSource( |
252 resource, String(test.nonce), | 253 resource, String(test.nonce), |
253 ResourceRequest::RedirectStatus::NoRedirect, | 254 ResourceRequest::RedirectStatus::NoRedirect, |
254 SecurityViolationReportingPolicy::SuppressReporting)); | 255 SecurityViolationReportingPolicy::SuppressReporting)); |
255 | 256 |
256 // Report-only 'style-src' | 257 // Report-only 'style-src' |
257 directiveList = createList(String("default-src ") + test.list, | 258 directiveList = createList(String("default-src ") + test.list, |
258 ContentSecurityPolicyHeaderTypeReport); | 259 ContentSecurityPolicyHeaderTypeReport); |
259 EXPECT_EQ(test.expected, | 260 EXPECT_EQ(test.expected, |
260 directiveList->allowScriptFromSource( | 261 directiveList->allowScriptFromSource( |
261 resource, String(test.nonce), ParserInserted, | 262 resource, String(test.nonce), IntegrityMetadataSet(), |
262 ResourceRequest::RedirectStatus::NoRedirect, | 263 ParserInserted, ResourceRequest::RedirectStatus::NoRedirect, |
263 SecurityViolationReportingPolicy::SuppressReporting)); | 264 SecurityViolationReportingPolicy::SuppressReporting)); |
264 EXPECT_EQ(test.expected, | 265 EXPECT_EQ(test.expected, |
265 directiveList->allowStyleFromSource( | 266 directiveList->allowStyleFromSource( |
266 resource, String(test.nonce), | 267 resource, String(test.nonce), |
267 ResourceRequest::RedirectStatus::NoRedirect, | 268 ResourceRequest::RedirectStatus::NoRedirect, |
268 SecurityViolationReportingPolicy::SuppressReporting)); | 269 SecurityViolationReportingPolicy::SuppressReporting)); |
269 | 270 |
270 // Enforce 'style-src' | 271 // Enforce 'style-src' |
271 directiveList = createList(String("default-src ") + test.list, | 272 directiveList = createList(String("default-src ") + test.list, |
272 ContentSecurityPolicyHeaderTypeEnforce); | 273 ContentSecurityPolicyHeaderTypeEnforce); |
273 EXPECT_EQ(test.expected, | 274 EXPECT_EQ(test.expected, |
274 directiveList->allowScriptFromSource( | 275 directiveList->allowScriptFromSource( |
275 resource, String(test.nonce), ParserInserted, | 276 resource, String(test.nonce), IntegrityMetadataSet(), |
276 ResourceRequest::RedirectStatus::NoRedirect, | 277 ParserInserted, ResourceRequest::RedirectStatus::NoRedirect, |
277 SecurityViolationReportingPolicy::SuppressReporting)); | 278 SecurityViolationReportingPolicy::SuppressReporting)); |
278 EXPECT_EQ(test.expected, | 279 EXPECT_EQ(test.expected, |
279 directiveList->allowStyleFromSource( | 280 directiveList->allowStyleFromSource( |
280 resource, String(test.nonce), | 281 resource, String(test.nonce), |
281 ResourceRequest::RedirectStatus::NoRedirect, | 282 ResourceRequest::RedirectStatus::NoRedirect, |
282 SecurityViolationReportingPolicy::SuppressReporting)); | 283 SecurityViolationReportingPolicy::SuppressReporting)); |
283 } | 284 } |
284 } | 285 } |
285 | 286 |
| 287 TEST_F(CSPDirectiveListTest, AllowScriptFromSourceWithHash) { |
| 288 struct TestCase { |
| 289 const char* list; |
| 290 const char* url; |
| 291 const char* integrity; |
| 292 bool expected; |
| 293 } cases[] = { |
| 294 // Doesn't affect lists without hashes. |
| 295 {"https://example.com", "https://example.com/file", "sha256-yay", true}, |
| 296 {"https://example.com", "https://example.com/file", "sha256-boo", true}, |
| 297 {"https://example.com", "https://example.com/file", "", true}, |
| 298 {"https://example.com", "https://not.example.com/file", "sha256-yay", |
| 299 false}, |
| 300 {"https://example.com", "https://not.example.com/file", "sha256-boo", |
| 301 false}, |
| 302 {"https://example.com", "https://not.example.com/file", "", false}, |
| 303 |
| 304 // Doesn't affect URLs that match the whitelist. |
| 305 {"https://example.com 'sha256-yay'", "https://example.com/file", |
| 306 "sha256-yay", true}, |
| 307 {"https://example.com 'sha256-yay'", "https://example.com/file", |
| 308 "sha256-boo", true}, |
| 309 {"https://example.com 'sha256-yay'", "https://example.com/file", "", |
| 310 true}, |
| 311 |
| 312 // Does affect URLs that don't match the whitelist. |
| 313 {"https://example.com 'sha256-yay'", "https://not.example.com/file", |
| 314 "sha256-yay", true}, |
| 315 {"https://example.com 'sha256-yay'", "https://not.example.com/file", |
| 316 "sha256-boo", false}, |
| 317 {"https://example.com 'sha256-yay'", "https://not.example.com/file", "", |
| 318 false}, |
| 319 |
| 320 // Both algorithm and digest must match. |
| 321 {"'sha256-yay'", "https://a.com/file", "sha384-yay", false}, |
| 322 |
| 323 // Sha-1 is not supported, but -384 and -512 are. |
| 324 {"'sha1-yay'", "https://a.com/file", "sha1-yay", false}, |
| 325 {"'sha384-yay'", "https://a.com/file", "sha384-yay", true}, |
| 326 {"'sha512-yay'", "https://a.com/file", "sha512-yay", true}, |
| 327 |
| 328 // Unknown (or future) hash algorithms don't work. |
| 329 {"'asdf256-yay'", "https://a.com/file", "asdf256-yay", false}, |
| 330 |
| 331 // But they also don't interfere. |
| 332 {"'sha256-yay'", "https://a.com/file", "sha256-yay asdf256-boo", true}, |
| 333 |
| 334 // Additional whitelisted hashes in the CSP don't interfere. |
| 335 {"'sha256-yay' 'sha384-boo'", "https://a.com/file", "sha256-yay", true}, |
| 336 {"'sha256-yay' 'sha384-boo'", "https://a.com/file", "sha384-boo", true}, |
| 337 |
| 338 // All integrity hashes must appear in the CSP (and match). |
| 339 {"'sha256-yay'", "https://a.com/file", "sha256-yay sha384-boo", false}, |
| 340 {"'sha384-boo'", "https://a.com/file", "sha256-yay sha384-boo", false}, |
| 341 {"'sha256-yay' 'sha384-boo'", "https://a.com/file", |
| 342 "sha256-yay sha384-yay", false}, |
| 343 {"'sha256-yay' 'sha384-boo'", "https://a.com/file", |
| 344 "sha256-boo sha384-boo", false}, |
| 345 {"'sha256-yay' 'sha384-boo'", "https://a.com/file", |
| 346 "sha256-yay sha384-boo", true}, |
| 347 |
| 348 // At least one integrity hash must be present. |
| 349 {"'sha256-yay'", "https://a.com/file", "", false}, |
| 350 }; |
| 351 |
| 352 for (const auto& test : cases) { |
| 353 SCOPED_TRACE(testing::Message() |
| 354 << "List: `" << test.list << "`, URL: `" << test.url |
| 355 << "`, Integrity: `" << test.integrity << "`"); |
| 356 KURL resource = KURL(KURL(), test.url); |
| 357 |
| 358 IntegrityMetadataSet integrityMetadata; |
| 359 ASSERT_EQ(SubresourceIntegrity::IntegrityParseValidResult, |
| 360 SubresourceIntegrity::parseIntegrityAttribute(test.integrity, |
| 361 integrityMetadata)); |
| 362 |
| 363 // Report-only 'script-src' |
| 364 Member<CSPDirectiveList> directiveList = |
| 365 createList(String("script-src ") + test.list, |
| 366 ContentSecurityPolicyHeaderTypeReport); |
| 367 EXPECT_EQ(test.expected, |
| 368 directiveList->allowScriptFromSource( |
| 369 resource, String(), integrityMetadata, ParserInserted, |
| 370 ResourceRequest::RedirectStatus::NoRedirect, |
| 371 SecurityViolationReportingPolicy::SuppressReporting)); |
| 372 |
| 373 // Enforce 'script-src' |
| 374 directiveList = createList(String("script-src ") + test.list, |
| 375 ContentSecurityPolicyHeaderTypeEnforce); |
| 376 EXPECT_EQ(test.expected, |
| 377 directiveList->allowScriptFromSource( |
| 378 resource, String(), integrityMetadata, ParserInserted, |
| 379 ResourceRequest::RedirectStatus::NoRedirect, |
| 380 SecurityViolationReportingPolicy::SuppressReporting)); |
| 381 } |
| 382 } |
| 383 |
286 TEST_F(CSPDirectiveListTest, allowRequestWithoutIntegrity) { | 384 TEST_F(CSPDirectiveListTest, allowRequestWithoutIntegrity) { |
287 struct TestCase { | 385 struct TestCase { |
288 const char* list; | 386 const char* list; |
289 const char* url; | 387 const char* url; |
290 const WebURLRequest::RequestContext context; | 388 const WebURLRequest::RequestContext context; |
291 bool expected; | 389 bool expected; |
292 } cases[] = { | 390 } cases[] = { |
293 | 391 |
294 {"require-sri-for script", "https://example.com/file", | 392 {"require-sri-for script", "https://example.com/file", |
295 WebURLRequest::RequestContextScript, false}, | 393 WebURLRequest::RequestContextScript, false}, |
(...skipping 726 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1022 CSPDirectiveList::getSourceVector(test.directive, policyVector).size(), | 1120 CSPDirectiveList::getSourceVector(test.directive, policyVector).size(), |
1023 udpatedTotal); | 1121 udpatedTotal); |
1024 EXPECT_EQ(CSPDirectiveList::getSourceVector( | 1122 EXPECT_EQ(CSPDirectiveList::getSourceVector( |
1025 ContentSecurityPolicy::DirectiveType::ChildSrc, policyVector) | 1123 ContentSecurityPolicy::DirectiveType::ChildSrc, policyVector) |
1026 .size(), | 1124 .size(), |
1027 expectedChildSrc); | 1125 expectedChildSrc); |
1028 } | 1126 } |
1029 } | 1127 } |
1030 | 1128 |
1031 } // namespace blink | 1129 } // namespace blink |
OLD | NEW |