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 hash algorithms don't work. | |
329 {"'asdf256-yay'", "https://a.com/file", "asdf256-yay", false}, | |
330 | |
331 // Additional whitelisted hashes in the CSP don't interfere. | |
332 {"'sha256-yay' 'sha384-boo'", "https://a.com/file", "sha256-yay", true}, | |
333 {"'sha256-yay' 'sha384-boo'", "https://a.com/file", "sha384-boo", true}, | |
334 | |
335 // All integrity hashes must appear in the CSP (and match). | |
336 {"'sha256-yay'", "https://a.com/file", "sha256-yay sha384-boo", false}, | |
337 {"'sha384-boo'", "https://a.com/file", "sha256-yay sha384-boo", false}, | |
338 {"'sha256-yay' 'sha384-boo'", "https://a.com/file", | |
339 "sha256-yay sha384-yay", false}, | |
340 {"'sha256-yay' 'sha384-boo'", "https://a.com/file", | |
341 "sha256-boo sha384-boo", false}, | |
342 {"'sha256-yay' 'sha384-boo'", "https://a.com/file", | |
343 "sha256-yay sha384-boo", true}, | |
344 | |
345 // At least one integrity hash must be present. | |
346 {"'sha256-yay'", "https://a.com/file", "", false}, | |
347 }; | |
348 | |
349 for (const auto& test : cases) { | |
350 SCOPED_TRACE(testing::Message() | |
351 << "List: `" << test.list << "`, URL: `" << test.url << "`"); | |
Mike West
2017/04/04 13:59:46
You'll probably want to add `test.integrity` in he
Marc Treib
2017/04/04 14:17:21
Good catch, done.
| |
352 KURL resource = KURL(KURL(), test.url); | |
353 | |
354 IntegrityMetadataSet integrityMetadata; | |
355 ASSERT_EQ(SubresourceIntegrity::IntegrityParseValidResult, | |
356 SubresourceIntegrity::parseIntegrityAttribute(test.integrity, | |
357 integrityMetadata)); | |
358 | |
359 // Report-only 'script-src' | |
360 Member<CSPDirectiveList> directiveList = | |
361 createList(String("script-src ") + test.list, | |
362 ContentSecurityPolicyHeaderTypeReport); | |
363 EXPECT_EQ(test.expected, | |
Mike West
2017/04/04 13:59:46
Shouldn't this be `EXPECT_TRUE`, if we're only in
Marc Treib
2017/04/04 14:17:21
Hm, good question. I just copied this from AllowFr
Marc Treib
2017/04/04 14:29:49
I'm confused now. There's ContentSecurityPolicyHea
| |
364 directiveList->allowScriptFromSource( | |
365 resource, String(), integrityMetadata, ParserInserted, | |
366 ResourceRequest::RedirectStatus::NoRedirect, | |
367 SecurityViolationReportingPolicy::SuppressReporting)); | |
368 | |
369 // Enforce 'script-src' | |
370 directiveList = createList(String("script-src ") + test.list, | |
371 ContentSecurityPolicyHeaderTypeEnforce); | |
372 EXPECT_EQ(test.expected, | |
373 directiveList->allowScriptFromSource( | |
374 resource, String(), integrityMetadata, ParserInserted, | |
375 ResourceRequest::RedirectStatus::NoRedirect, | |
376 SecurityViolationReportingPolicy::SuppressReporting)); | |
377 } | |
378 } | |
379 | |
286 TEST_F(CSPDirectiveListTest, allowRequestWithoutIntegrity) { | 380 TEST_F(CSPDirectiveListTest, allowRequestWithoutIntegrity) { |
287 struct TestCase { | 381 struct TestCase { |
288 const char* list; | 382 const char* list; |
289 const char* url; | 383 const char* url; |
290 const WebURLRequest::RequestContext context; | 384 const WebURLRequest::RequestContext context; |
291 bool expected; | 385 bool expected; |
292 } cases[] = { | 386 } cases[] = { |
293 | 387 |
294 {"require-sri-for script", "https://example.com/file", | 388 {"require-sri-for script", "https://example.com/file", |
295 WebURLRequest::RequestContextScript, false}, | 389 WebURLRequest::RequestContextScript, false}, |
(...skipping 726 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1022 CSPDirectiveList::getSourceVector(test.directive, policyVector).size(), | 1116 CSPDirectiveList::getSourceVector(test.directive, policyVector).size(), |
1023 udpatedTotal); | 1117 udpatedTotal); |
1024 EXPECT_EQ(CSPDirectiveList::getSourceVector( | 1118 EXPECT_EQ(CSPDirectiveList::getSourceVector( |
1025 ContentSecurityPolicy::DirectiveType::ChildSrc, policyVector) | 1119 ContentSecurityPolicy::DirectiveType::ChildSrc, policyVector) |
1026 .size(), | 1120 .size(), |
1027 expectedChildSrc); | 1121 expectedChildSrc); |
1028 } | 1122 } |
1029 } | 1123 } |
1030 | 1124 |
1031 } // namespace blink | 1125 } // namespace blink |
OLD | NEW |