Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1232)

Side by Side Diff: third_party/WebKit/Source/core/frame/csp/CSPDirectiveListTest.cpp

Issue 2784753003: CSP: Enable whitelisting of external JavaScript via hashes (Closed)
Patch Set: rebase Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698