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

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

Issue 2404373003: Experimental Feature: Allow-CSP-From header (Closed)
Patch Set: Created 4 years, 2 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 /* 1 /*
2 * Copyright (C) 2011 Google, Inc. All rights reserved. 2 * Copyright (C) 2011 Google, Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 ContentSecurityPolicyHeaderType type, 304 ContentSecurityPolicyHeaderType type,
305 ContentSecurityPolicyHeaderSource source) { 305 ContentSecurityPolicyHeaderSource source) {
306 addAndReportPolicyFromHeaderValue(header, type, source); 306 addAndReportPolicyFromHeaderValue(header, type, source);
307 307
308 // This might be called after we've been bound to an execution context. For 308 // This might be called after we've been bound to an execution context. For
309 // example, a <meta> element might be injected after page load. 309 // example, a <meta> element might be injected after page load.
310 if (m_executionContext) 310 if (m_executionContext)
311 applyPolicySideEffectsToExecutionContext(); 311 applyPolicySideEffectsToExecutionContext();
312 } 312 }
313 313
314 bool ContentSecurityPolicy::checkAllowBlanketEnforcement(
amalika 2016/10/11 19:06:46 This is the most important function. After I ran
315 const ResourceResponse& response,
316 const KURL& parentUrl) {
317 if (response.url().isEmpty() || response.url().protocolIsAbout() ||
318 response.url().protocolIsAbout() || response.url().protocolIs("blob") ||
319 response.url().protocolIs("filesystem")) {
320 return true;
321 }
322
323 if (parentUrl.protocol() == response.url().protocol() &&
324 parentUrl.host() == response.url().host() &&
325 parentUrl.port() == response.url().port()) {
326 return true;
327 }
328
329 HTTPHeaderMap::const_iterator it =
330 response.httpHeaderFields().find(HTTPNames::Allow_CSP_From);
331
332 String header =
333 it != response.httpHeaderFields().end() ? it->value : nullAtom;
334
335 if (header.isEmpty() || !header.containsOnlyASCII())
336 return false;
337
338 Vector<String> headers;
339 header.split(',', headers);
340 for (size_t i = 0; i < headers.size(); i++) {
341 String currentHeader = headers[i].stripWhiteSpace();
342 if (equalIgnoringCase(currentHeader, "*")) {
343 return true;
344 }
345 const KURL allowed(ParsedURLString, currentHeader);
346 if (allowed.isValid() && parentUrl.protocol() == allowed.protocol() &&
347 parentUrl.host() == allowed.host() &&
348 parentUrl.port() == allowed.port()) {
349 return true;
350 }
351 }
352
353 return false;
354 }
355
314 void ContentSecurityPolicy::addPolicyFromHeaderValue( 356 void ContentSecurityPolicy::addPolicyFromHeaderValue(
315 const String& header, 357 const String& header,
316 ContentSecurityPolicyHeaderType type, 358 ContentSecurityPolicyHeaderType type,
317 ContentSecurityPolicyHeaderSource source) { 359 ContentSecurityPolicyHeaderSource source) {
318 // If this is a report-only header inside a <meta> element, bail out. 360 // If this is a report-only header inside a <meta> element, bail out.
319 if (source == ContentSecurityPolicyHeaderSourceMeta && 361 if (source == ContentSecurityPolicyHeaderSourceMeta &&
320 type == ContentSecurityPolicyHeaderTypeReport) { 362 type == ContentSecurityPolicyHeaderTypeReport) {
321 reportReportOnlyInMeta(header); 363 reportReportOnlyInMeta(header);
322 return; 364 return;
323 } 365 }
(...skipping 26 matching lines...) Expand all
350 m_disableEvalErrorMessage.isNull()) 392 m_disableEvalErrorMessage.isNull())
351 m_disableEvalErrorMessage = policy->evalDisabledErrorMessage(); 393 m_disableEvalErrorMessage = policy->evalDisabledErrorMessage();
352 394
353 m_policies.append(policy.release()); 395 m_policies.append(policy.release());
354 396
355 // Skip the comma, and begin the next header from the current position. 397 // Skip the comma, and begin the next header from the current position.
356 ASSERT(position == end || *position == ','); 398 ASSERT(position == end || *position == ',');
357 skipExactly<UChar>(position, end, ','); 399 skipExactly<UChar>(position, end, ',');
358 begin = position; 400 begin = position;
359 } 401 }
360 } 402 }
361 403
362 void ContentSecurityPolicy::reportAccumulatedHeaders( 404 void ContentSecurityPolicy::reportAccumulatedHeaders(
363 FrameLoaderClient* client) const { 405 FrameLoaderClient* client) const {
364 // Notify the embedder about headers that have accumulated before the 406 // Notify the embedder about headers that have accumulated before the
365 // navigation got committed. See comments in 407 // navigation got committed. See comments in
366 // addAndReportPolicyFromHeaderValue for more details and context. 408 // addAndReportPolicyFromHeaderValue for more details and context.
367 DCHECK(client); 409 DCHECK(client);
368 for (const auto& policy : m_policies) { 410 for (const auto& policy : m_policies) {
369 client->didAddContentSecurityPolicy(policy->header(), policy->headerType(), 411 client->didAddContentSecurityPolicy(
370 policy->headerSource()); 412 policy->header(), policy->headerType(), policy->headerSource());
371 } 413 }
372 } 414 }
373 415
374 void ContentSecurityPolicy::addAndReportPolicyFromHeaderValue( 416 void ContentSecurityPolicy::addAndReportPolicyFromHeaderValue(
375 const String& header, 417 const String& header,
376 ContentSecurityPolicyHeaderType type, 418 ContentSecurityPolicyHeaderType type,
377 ContentSecurityPolicyHeaderSource source) { 419 ContentSecurityPolicyHeaderSource source) {
378 // Notify about the new header, so that it can be reported back to the 420 // Notify about the new header, so that it can be reported back to the
379 // browser process. This is needed in order to: 421 // browser process. This is needed in order to:
380 // 1) replicate CSP directives (i.e. frame-src) to OOPIFs (only for now / 422 // 1) replicate CSP directives (i.e. frame-src) to OOPIFs (only for now /
381 // short-term). 423 // short-term).
382 // 2) enforce CSP in the browser process (not yet / long-term - see 424 // 2) enforce CSP in the browser process (not yet / long-term - see
383 // https://crbug.com/376522). 425 // https://crbug.com/376522).
384 if (document() && document()->frame()) 426 if (document() && document()->frame()) {
385 document()->frame()->client()->didAddContentSecurityPolicy(header, type, 427 document()->frame()->client()->didAddContentSecurityPolicy(header, type,
386 source); 428 source);
387 429 }
388 addPolicyFromHeaderValue(header, type, source); 430
389 } 431 addPolicyFromHeaderValue(header, type, source);
390 432 }
391 void ContentSecurityPolicy::setOverrideAllowInlineStyle(bool value) { 433
392 m_overrideInlineStyleAllowed = value; 434 void ContentSecurityPolicy::setOverrideAllowInlineStyle(bool value) {
393 } 435 m_overrideInlineStyleAllowed = value;
394 436 }
395 void ContentSecurityPolicy::setOverrideURLForSelf(const KURL& url) { 437
396 // Create a temporary CSPSource so that 'self' expressions can be resolved 438 void ContentSecurityPolicy::setOverrideURLForSelf(const KURL& url) {
397 // before we bind to an execution context (for 'frame-ancestor' resolution, 439 // Create a temporary CSPSource so that 'self' expressions can be resolved
398 // for example). This CSPSource will be overwritten when we bind this object 440 // before we bind to an execution context (for 'frame-ancestor' resolution,
399 // to an execution context. 441 // for example). This CSPSource will be overwritten when we bind this object
400 RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url); 442 // to an execution context.
401 m_selfProtocol = origin->protocol(); 443 RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
402 m_selfSource = 444 m_selfProtocol = origin->protocol();
403 new CSPSource(this, m_selfProtocol, origin->host(), origin->port(), 445 m_selfSource =
404 String(), CSPSource::NoWildcard, CSPSource::NoWildcard); 446 new CSPSource(this, m_selfProtocol, origin->host(), origin->port(),
405 } 447 String(), CSPSource::NoWildcard, CSPSource::NoWildcard);
406 448 }
407 std::unique_ptr<Vector<CSPHeaderAndType>> ContentSecurityPolicy::headers() 449
408 const { 450 std::unique_ptr<Vector<CSPHeaderAndType>> ContentSecurityPolicy::headers()
409 std::unique_ptr<Vector<CSPHeaderAndType>> headers = 451 const {
410 wrapUnique(new Vector<CSPHeaderAndType>); 452 std::unique_ptr<Vector<CSPHeaderAndType>> headers =
411 for (const auto& policy : m_policies) { 453 wrapUnique(new Vector<CSPHeaderAndType>);
412 CSPHeaderAndType headerAndType(policy->header(), policy->headerType()); 454 for (const auto& policy : m_policies) {
413 headers->append(headerAndType); 455 CSPHeaderAndType headerAndType(policy->header(), policy->headerType());
414 } 456 headers->append(headerAndType);
415 return headers; 457 }
416 } 458 return headers;
417 459 }
418 template <bool (CSPDirectiveList::*allowed)( 460
419 ContentSecurityPolicy::ReportingStatus) const> 461 template <bool (CSPDirectiveList::*allowed)(
420 bool isAllowedByAll(const CSPDirectiveListVector& policies, 462 ContentSecurityPolicy::ReportingStatus) const>
421 ContentSecurityPolicy::ReportingStatus reportingStatus) { 463 bool isAllowedByAll(const CSPDirectiveListVector& policies,
422 bool isAllowed = true; 464 ContentSecurityPolicy::ReportingStatus reportingStatus) {
423 for (const auto& policy : policies) 465 bool isAllowed = true;
424 isAllowed &= (policy.get()->*allowed)(reportingStatus); 466 for (const auto& policy : policies)
425 return isAllowed; 467 isAllowed &= (policy.get()->*allowed)(reportingStatus);
426 } 468 return isAllowed;
427 469 }
428 template <bool (CSPDirectiveList::*allowed)( 470
429 ScriptState* scriptState, 471 template <bool (CSPDirectiveList::*allowed)(
430 ContentSecurityPolicy::ReportingStatus, 472 ScriptState* scriptState,
431 ContentSecurityPolicy::ExceptionStatus) const> 473 ContentSecurityPolicy::ReportingStatus,
432 bool isAllowedByAllWithStateAndExceptionStatus( 474 ContentSecurityPolicy::ExceptionStatus) const>
433 const CSPDirectiveListVector& policies, 475 bool isAllowedByAllWithStateAndExceptionStatus(
434 ScriptState* scriptState, 476 const CSPDirectiveListVector& policies,
435 ContentSecurityPolicy::ReportingStatus reportingStatus, 477 ScriptState* scriptState,
436 ContentSecurityPolicy::ExceptionStatus exceptionStatus) { 478 ContentSecurityPolicy::ReportingStatus reportingStatus,
437 bool isAllowed = true; 479 ContentSecurityPolicy::ExceptionStatus exceptionStatus) {
438 for (const auto& policy : policies) 480 bool isAllowed = true;
439 isAllowed &= 481 for (const auto& policy : policies) {
440 (policy.get()->*allowed)(scriptState, reportingStatus, exceptionStatus); 482 isAllowed &= (policy.get()->*allowed)(scriptState, reportingStatus,
441 return isAllowed; 483 exceptionStatus);
442 } 484 }
443 485 return isAllowed;
444 template <bool (CSPDirectiveList::*allowed)( 486 }
445 const String&, 487
446 const WTF::OrdinalNumber&, 488 template <bool (CSPDirectiveList::*allowed)(
447 ContentSecurityPolicy::ReportingStatus) const> 489 const String&,
448 bool isAllowedByAllWithContext( 490 const WTF::OrdinalNumber&,
449 const CSPDirectiveListVector& policies, 491 ContentSecurityPolicy::ReportingStatus) const>
450 const String& contextURL, 492 bool isAllowedByAllWithContext(
451 const WTF::OrdinalNumber& contextLine, 493 const CSPDirectiveListVector& policies,
452 ContentSecurityPolicy::ReportingStatus reportingStatus) { 494 const String& contextURL,
453 bool isAllowed = true; 495 const WTF::OrdinalNumber& contextLine,
454 for (const auto& policy : policies) 496 ContentSecurityPolicy::ReportingStatus reportingStatus) {
455 isAllowed &= 497 bool isAllowed = true;
456 (policy.get()->*allowed)(contextURL, contextLine, reportingStatus); 498 for (const auto& policy : policies) {
457 return isAllowed; 499 isAllowed &=
458 } 500 (policy.get()->*allowed)(contextURL, contextLine, reportingStatus);
459 501 }
460 template < 502 return isAllowed;
461 bool (CSPDirectiveList::*allowed)(const String&, 503 }
462 const String&, 504
463 const WTF::OrdinalNumber&, 505 template <
464 ContentSecurityPolicy::ReportingStatus, 506 bool (CSPDirectiveList::*allowed)(const String&,
465 const String& content) const> 507 const String&,
466 bool isAllowedByAllWithContextAndContent( 508 const WTF::OrdinalNumber&,
467 const CSPDirectiveListVector& policies, 509 ContentSecurityPolicy::ReportingStatus,
468 const String& contextURL, 510 const String& content) const>
469 const String& nonce, 511 bool isAllowedByAllWithContextAndContent(
470 const WTF::OrdinalNumber& contextLine, 512 const CSPDirectiveListVector& policies,
471 ContentSecurityPolicy::ReportingStatus reportingStatus, 513 const String& contextURL,
472 const String& content) { 514 const String& nonce,
473 bool isAllowed = true; 515 const WTF::OrdinalNumber& contextLine,
474 for (const auto& policy : policies) 516 ContentSecurityPolicy::ReportingStatus reportingStatus,
475 isAllowed &= (policy.get()->*allowed)(contextURL, nonce, contextLine, 517 const String& content) {
476 reportingStatus, content); 518 bool isAllowed = true;
477 return isAllowed; 519 for (const auto& policy : policies) {
478 } 520 isAllowed &= (policy.get()->*allowed)(contextURL, nonce, contextLine,
479 521 reportingStatus, content);
480 template < 522 }
481 bool (CSPDirectiveList::*allowed)(const String&, 523 return isAllowed;
482 const String&, 524 }
483 ParserDisposition, 525
484 const WTF::OrdinalNumber&, 526 template <
485 ContentSecurityPolicy::ReportingStatus, 527 bool (CSPDirectiveList::*allowed)(const String&,
486 const String& content) const> 528 const String&,
487 bool isAllowedByAllWithContextAndContentAndParser( 529 ParserDisposition,
488 const CSPDirectiveListVector& policies, 530 const WTF::OrdinalNumber&,
489 const String& contextURL, 531 ContentSecurityPolicy::ReportingStatus,
490 const String& nonce, 532 const String& content) const>
491 ParserDisposition parserDisposition, 533 bool isAllowedByAllWithContextAndContentAndParser(
492 const WTF::OrdinalNumber& contextLine, 534 const CSPDirectiveListVector& policies,
493 ContentSecurityPolicy::ReportingStatus reportingStatus, 535 const String& contextURL,
494 const String& content) { 536 const String& nonce,
495 bool isAllowed = true; 537 ParserDisposition parserDisposition,
496 for (const auto& policy : policies) { 538 const WTF::OrdinalNumber& contextLine,
497 isAllowed &= 539 ContentSecurityPolicy::ReportingStatus reportingStatus,
498 (policy.get()->*allowed)(contextURL, nonce, parserDisposition, 540 const String& content) {
499 contextLine, reportingStatus, content); 541 bool isAllowed = true;
500 } 542 for (const auto& policy : policies) {
501 return isAllowed; 543 isAllowed &=
502 } 544 (policy.get()->*allowed)(contextURL, nonce, parserDisposition,
503 545 contextLine, reportingStatus, content);
504 template <bool (CSPDirectiveList::*allowed)(const CSPHashValue&, 546 }
505 ContentSecurityPolicy::InlineType) 547 return isAllowed;
506 const> 548 }
507 bool isAllowedByAllWithHash(const CSPDirectiveListVector& policies, 549
508 const CSPHashValue& hashValue, 550 template <bool (CSPDirectiveList::*allowed)(const CSPHashValue&,
509 ContentSecurityPolicy::InlineType type) { 551 ContentSecurityPolicy::InlineType)
510 bool isAllowed = true; 552 const>
511 for (const auto& policy : policies) 553 bool isAllowedByAllWithHash(const CSPDirectiveListVector& policies,
512 isAllowed &= (policy.get()->*allowed)(hashValue, type); 554 const CSPHashValue& hashValue,
513 return isAllowed; 555 ContentSecurityPolicy::InlineType type) {
514 } 556 bool isAllowed = true;
515 557 for (const auto& policy : policies)
516 template <bool (CSPDirectiveList::*allowFromURL)( 558 isAllowed &= (policy.get()->*allowed)(hashValue, type);
517 const KURL&, 559 return isAllowed;
518 RedirectStatus, 560 }
519 ContentSecurityPolicy::ReportingStatus) const> 561
520 bool isAllowedByAllWithURL( 562 template <bool (CSPDirectiveList::*allowFromURL)(
521 const CSPDirectiveListVector& policies, 563 const KURL&,
522 const KURL& url, 564 RedirectStatus,
523 RedirectStatus redirectStatus, 565 ContentSecurityPolicy::ReportingStatus) const>
524 ContentSecurityPolicy::ReportingStatus reportingStatus) { 566 bool isAllowedByAllWithURL(
525 if (SchemeRegistry::schemeShouldBypassContentSecurityPolicy(url.protocol())) 567 const CSPDirectiveListVector& policies,
568 const KURL& url,
569 RedirectStatus redirectStatus,
570 ContentSecurityPolicy::ReportingStatus reportingStatus) {
571 if (SchemeRegistry::schemeShouldBypassContentSecurityPolicy(url.protocol()))
572 return true;
573
574 bool isAllowed = true;
575 for (const auto& policy : policies) {
576 isAllowed &=
577 (policy.get()->*allowFromURL)(url, redirectStatus, reportingStatus);
578 }
579 return isAllowed;
580 }
581
582 template <bool (CSPDirectiveList::*allowFromURLWithNonce)(
583 const KURL&,
584 const String& nonce,
585 RedirectStatus,
586 ContentSecurityPolicy::ReportingStatus) const>
587 bool isAllowedByAllWithURLWithNonce(
588 const CSPDirectiveListVector& policies,
589 const KURL& url,
590 const String& nonce,
591 RedirectStatus redirectStatus,
592 ContentSecurityPolicy::ReportingStatus reportingStatus) {
593 if (SchemeRegistry::schemeShouldBypassContentSecurityPolicy(url.protocol()))
594 return true;
595
596 bool isAllowed = true;
597 for (const auto& policy : policies) {
598 isAllowed &= (policy.get()->*allowFromURLWithNonce)(
599 url, nonce, redirectStatus, reportingStatus);
600 }
601 return isAllowed;
602 }
603
604 template <bool (CSPDirectiveList::*allowFromURLWithNonceAndParser)(
605 const KURL&,
606 const String& nonce,
607 ParserDisposition parserDisposition,
608 RedirectStatus,
609 ContentSecurityPolicy::ReportingStatus) const>
610 bool isAllowedByAllWithURLNonceAndParser(
611 const CSPDirectiveListVector& policies,
612 const KURL& url,
613 const String& nonce,
614 ParserDisposition parserDisposition,
615 RedirectStatus redirectStatus,
616 ContentSecurityPolicy::ReportingStatus reportingStatus) {
617 if (SchemeRegistry::schemeShouldBypassContentSecurityPolicy(url.protocol()))
618 return true;
619
620 bool isAllowed = true;
621 for (const auto& policy : policies) {
622 isAllowed &= (policy.get()->*allowFromURLWithNonceAndParser)(
623 url, nonce, parserDisposition, redirectStatus, reportingStatus);
624 }
625 return isAllowed;
626 }
627
628 template <bool (CSPDirectiveList::*allowed)(
629 LocalFrame*,
630 const KURL&,
631 ContentSecurityPolicy::ReportingStatus) const>
632 bool isAllowedByAllWithFrame(
633 const CSPDirectiveListVector& policies,
634 LocalFrame* frame,
635 const KURL& url,
636 ContentSecurityPolicy::ReportingStatus reportingStatus) {
637 bool isAllowed = true;
638 for (const auto& policy : policies)
639 isAllowed &= (policy.get()->*allowed)(frame, url, reportingStatus);
640 return isAllowed;
641 }
642
643 template <bool (CSPDirectiveList::*allowed)(const CSPHashValue&,
644 ContentSecurityPolicy::InlineType)
645 const>
646 bool checkDigest(const String& source,
647 ContentSecurityPolicy::InlineType type,
648 uint8_t hashAlgorithmsUsed,
649 const CSPDirectiveListVector& policies) {
650 // Any additions or subtractions from this struct should also modify the
651 // respective entries in the kSupportedPrefixes array in
652 // CSPSourceList::parseHash().
653 static const struct {
654 ContentSecurityPolicyHashAlgorithm cspHashAlgorithm;
655 HashAlgorithm algorithm;
656 } kAlgorithmMap[] = {
657 {ContentSecurityPolicyHashAlgorithmSha1, HashAlgorithmSha1},
658 {ContentSecurityPolicyHashAlgorithmSha256, HashAlgorithmSha256},
659 {ContentSecurityPolicyHashAlgorithmSha384, HashAlgorithmSha384},
660 {ContentSecurityPolicyHashAlgorithmSha512, HashAlgorithmSha512}};
661
662 // Only bother normalizing the source/computing digests if there are any
663 // checks to be done.
664 if (hashAlgorithmsUsed == ContentSecurityPolicyHashAlgorithmNone)
665 return false;
666
667 StringUTF8Adaptor utf8Source(source);
668
669 for (const auto& algorithmMap : kAlgorithmMap) {
670 DigestValue digest;
671 if (algorithmMap.cspHashAlgorithm & hashAlgorithmsUsed) {
672 bool digestSuccess =
673 computeDigest(algorithmMap.algorithm, utf8Source.data(),
674 utf8Source.length(), digest);
675 if (digestSuccess &&
676 isAllowedByAllWithHash<allowed>(
677 policies, CSPHashValue(algorithmMap.cspHashAlgorithm, digest),
678 type))
679 return true;
680 }
681 }
682
683 return false;
684 }
685
686 bool ContentSecurityPolicy::allowJavaScriptURLs(
687 const String& contextURL,
688 const WTF::OrdinalNumber& contextLine,
689 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
690 return isAllowedByAllWithContext<&CSPDirectiveList::allowJavaScriptURLs>(
691 m_policies, contextURL, contextLine, reportingStatus);
692 }
693
694 bool ContentSecurityPolicy::allowInlineEventHandler(
695 const String& source,
696 const String& contextURL,
697 const WTF::OrdinalNumber& contextLine,
698 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
699 // Inline event handlers may be whitelisted by hash, if
700 // 'unsafe-hash-attributes' is present in a policy. Check against the digest
701 // of the |source| first before proceeding on to checking whether inline
702 // script is allowed.
703 if (checkDigest<&CSPDirectiveList::allowScriptHash>(
704 source, InlineType::Attribute, m_scriptHashAlgorithmsUsed,
705 m_policies))
706 return true;
707 return isAllowedByAllWithContext<
708 &CSPDirectiveList::allowInlineEventHandlers>(
709 m_policies, contextURL, contextLine, reportingStatus);
710 }
711
712 bool ContentSecurityPolicy::allowInlineScript(
713 const String& contextURL,
714 const String& nonce,
715 ParserDisposition parserDisposition,
716 const WTF::OrdinalNumber& contextLine,
717 const String& scriptContent,
718 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
719 return isAllowedByAllWithContextAndContentAndParser<
720 &CSPDirectiveList::allowInlineScript>(m_policies, contextURL, nonce,
721 parserDisposition, contextLine,
722 reportingStatus, scriptContent);
723 }
724
725 bool ContentSecurityPolicy::allowInlineStyle(
726 const String& contextURL,
727 const String& nonce,
728 const WTF::OrdinalNumber& contextLine,
729 const String& styleContent,
730 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
731 if (m_overrideInlineStyleAllowed)
732 return true;
733 return isAllowedByAllWithContextAndContent<
734 &CSPDirectiveList::allowInlineStyle>(m_policies, contextURL, nonce,
735 contextLine, reportingStatus,
736 styleContent);
737 }
738
739 bool ContentSecurityPolicy::allowEval(
740 ScriptState* scriptState,
741 ContentSecurityPolicy::ReportingStatus reportingStatus,
742 ContentSecurityPolicy::ExceptionStatus exceptionStatus) const {
743 return isAllowedByAllWithStateAndExceptionStatus<
744 &CSPDirectiveList::allowEval>(m_policies, scriptState, reportingStatus,
745 exceptionStatus);
746 }
747
748 String ContentSecurityPolicy::evalDisabledErrorMessage() const {
749 for (const auto& policy : m_policies) {
750 if (!policy->allowEval(0, SuppressReport))
751 return policy->evalDisabledErrorMessage();
752 }
753 return String();
754 }
755
756 bool ContentSecurityPolicy::allowPluginType(
757 const String& type,
758 const String& typeAttribute,
759 const KURL& url,
760 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
761 for (const auto& policy : m_policies) {
762 if (!policy->allowPluginType(type, typeAttribute, url, reportingStatus))
763 return false;
764 }
526 return true; 765 return true;
527 766 }
528 bool isAllowed = true; 767
529 for (const auto& policy : policies) 768 bool ContentSecurityPolicy::allowPluginTypeForDocument(
530 isAllowed &= 769 const Document& document,
531 (policy.get()->*allowFromURL)(url, redirectStatus, reportingStatus); 770 const String& type,
532 return isAllowed; 771 const String& typeAttribute,
533 } 772 const KURL& url,
534 773 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
535 template <bool (CSPDirectiveList::*allowFromURLWithNonce)( 774 if (document.contentSecurityPolicy() &&
536 const KURL&, 775 !document.contentSecurityPolicy()->allowPluginType(type, typeAttribute,
537 const String& nonce, 776 url))
538 RedirectStatus, 777 return false;
539 ContentSecurityPolicy::ReportingStatus) const> 778
540 bool isAllowedByAllWithURLWithNonce( 779 // CSP says that a plugin document in a nested browsing context should
541 const CSPDirectiveListVector& policies, 780 // inherit the plugin-types of its parent.
542 const KURL& url, 781 //
543 const String& nonce, 782 // FIXME: The plugin-types directive should be pushed down into the
544 RedirectStatus redirectStatus, 783 // current document instead of reaching up to the parent for it here.
545 ContentSecurityPolicy::ReportingStatus reportingStatus) { 784 LocalFrame* frame = document.frame();
546 if (SchemeRegistry::schemeShouldBypassContentSecurityPolicy(url.protocol())) 785 if (frame && frame->tree().parent() && document.isPluginDocument()) {
786 ContentSecurityPolicy* parentCSP =
787 frame->tree().parent()->securityContext()->contentSecurityPolicy();
788 if (parentCSP && !parentCSP->allowPluginType(type, typeAttribute, url))
789 return false;
790 }
791
547 return true; 792 return true;
548 793 }
549 bool isAllowed = true; 794
550 for (const auto& policy : policies) 795 bool ContentSecurityPolicy::allowScriptFromSource(
551 isAllowed &= (policy.get()->*allowFromURLWithNonce)( 796 const KURL& url,
552 url, nonce, redirectStatus, reportingStatus); 797 const String& nonce,
553 return isAllowed; 798 ParserDisposition parserDisposition,
554 } 799 RedirectStatus redirectStatus,
555 800 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
556 template <bool (CSPDirectiveList::*allowFromURLWithNonceAndParser)( 801 return isAllowedByAllWithURLNonceAndParser<
557 const KURL&, 802 &CSPDirectiveList::allowScriptFromSource>(
558 const String& nonce, 803 m_policies, url, nonce, parserDisposition, redirectStatus,
559 ParserDisposition parserDisposition, 804 reportingStatus);
560 RedirectStatus, 805 }
561 ContentSecurityPolicy::ReportingStatus) const> 806
562 bool isAllowedByAllWithURLNonceAndParser( 807 bool ContentSecurityPolicy::allowScriptWithHash(const String& source,
563 const CSPDirectiveListVector& policies, 808 InlineType type) const {
564 const KURL& url, 809 return checkDigest<&CSPDirectiveList::allowScriptHash>(
565 const String& nonce, 810 source, type, m_scriptHashAlgorithmsUsed, m_policies);
566 ParserDisposition parserDisposition, 811 }
567 RedirectStatus redirectStatus, 812
568 ContentSecurityPolicy::ReportingStatus reportingStatus) { 813 bool ContentSecurityPolicy::allowStyleWithHash(const String& source,
569 if (SchemeRegistry::schemeShouldBypassContentSecurityPolicy(url.protocol())) 814 InlineType type) const {
815 return checkDigest<&CSPDirectiveList::allowStyleHash>(
816 source, type, m_styleHashAlgorithmsUsed, m_policies);
817 }
818
819 bool ContentSecurityPolicy::allowRequestWithoutIntegrity(
820 WebURLRequest::RequestContext context,
821 const KURL& url,
822 RedirectStatus redirectStatus,
823 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
824 for (const auto& policy : m_policies) {
825 if (!policy->allowRequestWithoutIntegrity(context, url, redirectStatus,
826 reportingStatus))
827 return false;
828 }
570 return true; 829 return true;
571 830 }
572 bool isAllowed = true; 831
573 for (const auto& policy : policies) { 832 bool ContentSecurityPolicy::allowRequest(
574 isAllowed &= (policy.get()->*allowFromURLWithNonceAndParser)( 833 WebURLRequest::RequestContext context,
575 url, nonce, parserDisposition, redirectStatus, reportingStatus); 834 const KURL& url,
576 } 835 const String& nonce,
577 return isAllowed; 836 const IntegrityMetadataSet& integrityMetadata,
578 } 837 ParserDisposition parserDisposition,
579 838 RedirectStatus redirectStatus,
580 template <bool (CSPDirectiveList::*allowed)( 839 ReportingStatus reportingStatus) const {
581 LocalFrame*, 840 if (integrityMetadata.isEmpty() &&
582 const KURL&, 841 !allowRequestWithoutIntegrity(context, url, redirectStatus,
583 ContentSecurityPolicy::ReportingStatus) const> 842 reportingStatus))
584 bool isAllowedByAllWithFrame( 843 return false;
585 const CSPDirectiveListVector& policies, 844
586 LocalFrame* frame, 845 switch (context) {
587 const KURL& url, 846 case WebURLRequest::RequestContextAudio:
588 ContentSecurityPolicy::ReportingStatus reportingStatus) { 847 case WebURLRequest::RequestContextTrack:
589 bool isAllowed = true; 848 case WebURLRequest::RequestContextVideo:
590 for (const auto& policy : policies) 849 return allowMediaFromSource(url, redirectStatus, reportingStatus);
591 isAllowed &= (policy.get()->*allowed)(frame, url, reportingStatus); 850 case WebURLRequest::RequestContextBeacon:
592 return isAllowed; 851 case WebURLRequest::RequestContextEventSource:
593 } 852 case WebURLRequest::RequestContextFetch:
594 853 case WebURLRequest::RequestContextXMLHttpRequest:
595 template <bool (CSPDirectiveList::*allowed)(const CSPHashValue&, 854 return allowConnectToSource(url, redirectStatus, reportingStatus);
596 ContentSecurityPolicy::InlineType) 855 case WebURLRequest::RequestContextEmbed:
597 const> 856 case WebURLRequest::RequestContextObject:
598 bool checkDigest(const String& source, 857 return allowObjectFromSource(url, redirectStatus, reportingStatus);
599 ContentSecurityPolicy::InlineType type, 858 case WebURLRequest::RequestContextFavicon:
600 uint8_t hashAlgorithmsUsed, 859 case WebURLRequest::RequestContextImage:
601 const CSPDirectiveListVector& policies) { 860 case WebURLRequest::RequestContextImageSet:
602 // Any additions or subtractions from this struct should also modify the 861 return allowImageFromSource(url, redirectStatus, reportingStatus);
603 // respective entries in the kSupportedPrefixes array in 862 case WebURLRequest::RequestContextFont:
604 // CSPSourceList::parseHash(). 863 return allowFontFromSource(url, redirectStatus, reportingStatus);
605 static const struct { 864 case WebURLRequest::RequestContextForm:
606 ContentSecurityPolicyHashAlgorithm cspHashAlgorithm; 865 return allowFormAction(url, redirectStatus, reportingStatus);
607 HashAlgorithm algorithm; 866 case WebURLRequest::RequestContextFrame:
608 } kAlgorithmMap[] = { 867 case WebURLRequest::RequestContextIframe:
609 {ContentSecurityPolicyHashAlgorithmSha1, HashAlgorithmSha1}, 868 return allowChildFrameFromSource(url, redirectStatus, reportingStatus);
610 {ContentSecurityPolicyHashAlgorithmSha256, HashAlgorithmSha256}, 869 case WebURLRequest::RequestContextImport:
611 {ContentSecurityPolicyHashAlgorithmSha384, HashAlgorithmSha384}, 870 case WebURLRequest::RequestContextScript:
612 {ContentSecurityPolicyHashAlgorithmSha512, HashAlgorithmSha512}}; 871 return allowScriptFromSource(url, nonce, parserDisposition,
613 872 redirectStatus, reportingStatus);
614 // Only bother normalizing the source/computing digests if there are any 873 case WebURLRequest::RequestContextXSLT:
615 // checks to be done. 874 return allowScriptFromSource(url, nonce, parserDisposition,
616 if (hashAlgorithmsUsed == ContentSecurityPolicyHashAlgorithmNone) 875 redirectStatus, reportingStatus);
876 case WebURLRequest::RequestContextManifest:
877 return allowManifestFromSource(url, redirectStatus, reportingStatus);
878 case WebURLRequest::RequestContextServiceWorker:
879 case WebURLRequest::RequestContextSharedWorker:
880 case WebURLRequest::RequestContextWorker:
881 return allowWorkerContextFromSource(url, redirectStatus,
882 reportingStatus);
883 case WebURLRequest::RequestContextStyle:
884 return allowStyleFromSource(url, nonce, redirectStatus,
885 reportingStatus);
886 case WebURLRequest::RequestContextCSPReport:
887 case WebURLRequest::RequestContextDownload:
888 case WebURLRequest::RequestContextHyperlink:
889 case WebURLRequest::RequestContextInternal:
890 case WebURLRequest::RequestContextLocation:
891 case WebURLRequest::RequestContextPing:
892 case WebURLRequest::RequestContextPlugin:
893 case WebURLRequest::RequestContextPrefetch:
894 case WebURLRequest::RequestContextSubresource:
895 case WebURLRequest::RequestContextUnspecified:
896 return true;
897 }
898 NOTREACHED();
899 return true;
900 }
901
902 void ContentSecurityPolicy::usesScriptHashAlgorithms(uint8_t algorithms) {
903 m_scriptHashAlgorithmsUsed |= algorithms;
904 }
905
906 void ContentSecurityPolicy::usesStyleHashAlgorithms(uint8_t algorithms) {
907 m_styleHashAlgorithmsUsed |= algorithms;
908 }
909
910 bool ContentSecurityPolicy::allowObjectFromSource(
911 const KURL& url,
912 RedirectStatus redirectStatus,
913 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
914 return isAllowedByAllWithURL<&CSPDirectiveList::allowObjectFromSource>(
915 m_policies, url, redirectStatus, reportingStatus);
916 }
917
918 bool ContentSecurityPolicy::allowChildFrameFromSource(
919 const KURL& url,
920 RedirectStatus redirectStatus,
921 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
922 return isAllowedByAllWithURL<&CSPDirectiveList::allowChildFrameFromSource>(
923 m_policies, url, redirectStatus, reportingStatus);
924 }
925
926 bool ContentSecurityPolicy::allowImageFromSource(
927 const KURL& url,
928 RedirectStatus redirectStatus,
929 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
930 if (SchemeRegistry::schemeShouldBypassContentSecurityPolicy(
931 url.protocol(), SchemeRegistry::PolicyAreaImage))
932 return true;
933 return isAllowedByAllWithURL<&CSPDirectiveList::allowImageFromSource>(
934 m_policies, url, redirectStatus, reportingStatus);
935 }
936
937 bool ContentSecurityPolicy::allowStyleFromSource(
938 const KURL& url,
939 const String& nonce,
940 RedirectStatus redirectStatus,
941 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
942 if (SchemeRegistry::schemeShouldBypassContentSecurityPolicy(
943 url.protocol(), SchemeRegistry::PolicyAreaStyle))
944 return true;
945 return isAllowedByAllWithURLWithNonce<
946 &CSPDirectiveList::allowStyleFromSource>(
947 m_policies, url, nonce, redirectStatus, reportingStatus);
948 }
949
950 bool ContentSecurityPolicy::allowFontFromSource(
951 const KURL& url,
952 RedirectStatus redirectStatus,
953 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
954 return isAllowedByAllWithURL<&CSPDirectiveList::allowFontFromSource>(
955 m_policies, url, redirectStatus, reportingStatus);
956 }
957
958 bool ContentSecurityPolicy::allowMediaFromSource(
959 const KURL& url,
960 RedirectStatus redirectStatus,
961 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
962 return isAllowedByAllWithURL<&CSPDirectiveList::allowMediaFromSource>(
963 m_policies, url, redirectStatus, reportingStatus);
964 }
965
966 bool ContentSecurityPolicy::allowConnectToSource(
967 const KURL& url,
968 RedirectStatus redirectStatus,
969 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
970 return isAllowedByAllWithURL<&CSPDirectiveList::allowConnectToSource>(
971 m_policies, url, redirectStatus, reportingStatus);
972 }
973
974 bool ContentSecurityPolicy::allowFormAction(
975 const KURL& url,
976 RedirectStatus redirectStatus,
977 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
978 return isAllowedByAllWithURL<&CSPDirectiveList::allowFormAction>(
979 m_policies, url, redirectStatus, reportingStatus);
980 }
981
982 bool ContentSecurityPolicy::allowBaseURI(
983 const KURL& url,
984 RedirectStatus redirectStatus,
985 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
986 return isAllowedByAllWithURL<&CSPDirectiveList::allowBaseURI>(
987 m_policies, url, redirectStatus, reportingStatus);
988 }
989
990 bool ContentSecurityPolicy::allowWorkerContextFromSource(
991 const KURL& url,
992 RedirectStatus redirectStatus,
993 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
994 // CSP 1.1 moves workers from 'script-src' to the new 'child-src'. Measure
995 // the
996 // impact of this backwards-incompatible change.
997 if (Document* document = this->document()) {
998 UseCounter::count(*document, UseCounter::WorkerSubjectToCSP);
999 if (isAllowedByAllWithURL<&CSPDirectiveList::allowChildContextFromSource>(
1000 m_policies, url, redirectStatus, SuppressReport) &&
1001 !isAllowedByAllWithURLNonceAndParser<
1002 &CSPDirectiveList::allowScriptFromSource>(
1003 m_policies, url, AtomicString(), NotParserInserted,
1004 redirectStatus, SuppressReport)) {
1005 UseCounter::count(*document,
1006 UseCounter::WorkerAllowedByChildBlockedByScript);
1007 }
1008 }
1009
1010 return isAllowedByAllWithURL<
1011 &CSPDirectiveList::allowChildContextFromSource>(
1012 m_policies, url, redirectStatus, reportingStatus);
1013 }
1014
1015 bool ContentSecurityPolicy::allowManifestFromSource(
1016 const KURL& url,
1017 RedirectStatus redirectStatus,
1018 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
1019 return isAllowedByAllWithURL<&CSPDirectiveList::allowManifestFromSource>(
1020 m_policies, url, redirectStatus, reportingStatus);
1021 }
1022
1023 bool ContentSecurityPolicy::allowAncestors(
1024 LocalFrame* frame,
1025 const KURL& url,
1026 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
1027 return isAllowedByAllWithFrame<&CSPDirectiveList::allowAncestors>(
1028 m_policies, frame, url, reportingStatus);
1029 }
1030
1031 bool ContentSecurityPolicy::isFrameAncestorsEnforced() const {
1032 for (const auto& policy : m_policies) {
1033 if (policy->isFrameAncestorsEnforced())
1034 return true;
1035 }
617 return false; 1036 return false;
618 1037 }
619 StringUTF8Adaptor utf8Source(source); 1038
620 1039 bool ContentSecurityPolicy::isActive() const {
621 for (const auto& algorithmMap : kAlgorithmMap) { 1040 return !m_policies.isEmpty();
622 DigestValue digest; 1041 }
623 if (algorithmMap.cspHashAlgorithm & hashAlgorithmsUsed) { 1042
624 bool digestSuccess = 1043 ReflectedXSSDisposition ContentSecurityPolicy::getReflectedXSSDisposition()
625 computeDigest(algorithmMap.algorithm, utf8Source.data(), 1044 const {
626 utf8Source.length(), digest); 1045 ReflectedXSSDisposition disposition = ReflectedXSSUnset;
627 if (digestSuccess && 1046 for (const auto& policy : m_policies) {
628 isAllowedByAllWithHash<allowed>( 1047 if (policy->getReflectedXSSDisposition() > disposition) {
629 policies, CSPHashValue(algorithmMap.cspHashAlgorithm, digest), 1048 disposition =
630 type)) 1049 std::max(disposition, policy->getReflectedXSSDisposition());
1050 }
1051 }
1052 return disposition;
1053 }
1054
1055 bool ContentSecurityPolicy::didSetReferrerPolicy() const {
1056 for (const auto& policy : m_policies) {
1057 if (policy->didSetReferrerPolicy())
631 return true; 1058 return true;
632 } 1059 }
633 }
634
635 return false;
636 }
637
638 bool ContentSecurityPolicy::allowJavaScriptURLs(
639 const String& contextURL,
640 const WTF::OrdinalNumber& contextLine,
641 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
642 return isAllowedByAllWithContext<&CSPDirectiveList::allowJavaScriptURLs>(
643 m_policies, contextURL, contextLine, reportingStatus);
644 }
645
646 bool ContentSecurityPolicy::allowInlineEventHandler(
647 const String& source,
648 const String& contextURL,
649 const WTF::OrdinalNumber& contextLine,
650 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
651 // Inline event handlers may be whitelisted by hash, if
652 // 'unsafe-hash-attributes' is present in a policy. Check against the digest
653 // of the |source| first before proceeding on to checking whether inline
654 // script is allowed.
655 if (checkDigest<&CSPDirectiveList::allowScriptHash>(
656 source, InlineType::Attribute, m_scriptHashAlgorithmsUsed,
657 m_policies))
658 return true;
659 return isAllowedByAllWithContext<&CSPDirectiveList::allowInlineEventHandlers>(
660 m_policies, contextURL, contextLine, reportingStatus);
661 }
662
663 bool ContentSecurityPolicy::allowInlineScript(
664 const String& contextURL,
665 const String& nonce,
666 ParserDisposition parserDisposition,
667 const WTF::OrdinalNumber& contextLine,
668 const String& scriptContent,
669 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
670 return isAllowedByAllWithContextAndContentAndParser<
671 &CSPDirectiveList::allowInlineScript>(m_policies, contextURL, nonce,
672 parserDisposition, contextLine,
673 reportingStatus, scriptContent);
674 }
675
676 bool ContentSecurityPolicy::allowInlineStyle(
677 const String& contextURL,
678 const String& nonce,
679 const WTF::OrdinalNumber& contextLine,
680 const String& styleContent,
681 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
682 if (m_overrideInlineStyleAllowed)
683 return true;
684 return isAllowedByAllWithContextAndContent<
685 &CSPDirectiveList::allowInlineStyle>(m_policies, contextURL, nonce,
686 contextLine, reportingStatus,
687 styleContent);
688 }
689
690 bool ContentSecurityPolicy::allowEval(
691 ScriptState* scriptState,
692 ContentSecurityPolicy::ReportingStatus reportingStatus,
693 ContentSecurityPolicy::ExceptionStatus exceptionStatus) const {
694 return isAllowedByAllWithStateAndExceptionStatus<
695 &CSPDirectiveList::allowEval>(m_policies, scriptState, reportingStatus,
696 exceptionStatus);
697 }
698
699 String ContentSecurityPolicy::evalDisabledErrorMessage() const {
700 for (const auto& policy : m_policies) {
701 if (!policy->allowEval(0, SuppressReport))
702 return policy->evalDisabledErrorMessage();
703 }
704 return String();
705 }
706
707 bool ContentSecurityPolicy::allowPluginType(
708 const String& type,
709 const String& typeAttribute,
710 const KURL& url,
711 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
712 for (const auto& policy : m_policies) {
713 if (!policy->allowPluginType(type, typeAttribute, url, reportingStatus))
714 return false;
715 }
716 return true;
717 }
718
719 bool ContentSecurityPolicy::allowPluginTypeForDocument(
720 const Document& document,
721 const String& type,
722 const String& typeAttribute,
723 const KURL& url,
724 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
725 if (document.contentSecurityPolicy() &&
726 !document.contentSecurityPolicy()->allowPluginType(type, typeAttribute,
727 url))
728 return false; 1060 return false;
729 1061 }
730 // CSP says that a plugin document in a nested browsing context should 1062
731 // inherit the plugin-types of its parent. 1063 const KURL ContentSecurityPolicy::url() const {
732 // 1064 return m_executionContext->contextURL();
733 // FIXME: The plugin-types directive should be pushed down into the 1065 }
734 // current document instead of reaching up to the parent for it here. 1066
735 LocalFrame* frame = document.frame(); 1067 KURL ContentSecurityPolicy::completeURL(const String& url) const {
736 if (frame && frame->tree().parent() && document.isPluginDocument()) { 1068 return m_executionContext->contextCompleteURL(url);
737 ContentSecurityPolicy* parentCSP = 1069 }
738 frame->tree().parent()->securityContext()->contentSecurityPolicy(); 1070
739 if (parentCSP && !parentCSP->allowPluginType(type, typeAttribute, url)) 1071 void ContentSecurityPolicy::enforceSandboxFlags(SandboxFlags mask) {
740 return false; 1072 m_sandboxMask |= mask;
741 } 1073 }
742 1074
743 return true; 1075 void ContentSecurityPolicy::treatAsPublicAddress() {
744 } 1076 if (!RuntimeEnabledFeatures::corsRFC1918Enabled())
745 1077 return;
746 bool ContentSecurityPolicy::allowScriptFromSource( 1078 m_treatAsPublicAddress = true;
747 const KURL& url, 1079 }
748 const String& nonce, 1080
749 ParserDisposition parserDisposition, 1081 void ContentSecurityPolicy::enforceStrictMixedContentChecking() {
750 RedirectStatus redirectStatus, 1082 m_insecureRequestPolicy |= kBlockAllMixedContent;
751 ContentSecurityPolicy::ReportingStatus reportingStatus) const { 1083 }
752 return isAllowedByAllWithURLNonceAndParser< 1084
753 &CSPDirectiveList::allowScriptFromSource>( 1085 void ContentSecurityPolicy::upgradeInsecureRequests() {
754 m_policies, url, nonce, parserDisposition, redirectStatus, 1086 m_insecureRequestPolicy |= kUpgradeInsecureRequests;
755 reportingStatus); 1087 }
756 } 1088
757 1089 static String stripURLForUseInReport(Document* document,
758 bool ContentSecurityPolicy::allowScriptWithHash(const String& source, 1090 const KURL& url,
759 InlineType type) const { 1091 RedirectStatus redirectStatus,
760 return checkDigest<&CSPDirectiveList::allowScriptHash>( 1092 const String& effectiveDirective) {
761 source, type, m_scriptHashAlgorithmsUsed, m_policies); 1093 if (!url.isValid())
762 } 1094 return String();
763 1095 if (!url.isHierarchical() || url.protocolIs("file"))
764 bool ContentSecurityPolicy::allowStyleWithHash(const String& source, 1096 return url.protocol();
765 InlineType type) const { 1097
766 return checkDigest<&CSPDirectiveList::allowStyleHash>( 1098 // Until we're more careful about the way we deal with navigations in frames
767 source, type, m_styleHashAlgorithmsUsed, m_policies); 1099 // (and, by extension, in plugin documents), strip cross-origin 'frame-src'
768 } 1100 // and 'object-src' violations down to an origin. https://crbug.com/633306
769 1101 bool canSafelyExposeURL =
770 bool ContentSecurityPolicy::allowRequestWithoutIntegrity( 1102 document->getSecurityOrigin()->canRequest(url) ||
771 WebURLRequest::RequestContext context, 1103 (redirectStatus == RedirectStatus::NoRedirect &&
772 const KURL& url, 1104 !equalIgnoringCase(effectiveDirective,
773 RedirectStatus redirectStatus, 1105 ContentSecurityPolicy::FrameSrc) &&
774 ContentSecurityPolicy::ReportingStatus reportingStatus) const { 1106 !equalIgnoringCase(effectiveDirective,
775 for (const auto& policy : m_policies) { 1107 ContentSecurityPolicy::ObjectSrc));
776 if (!policy->allowRequestWithoutIntegrity(context, url, redirectStatus, 1108
777 reportingStatus)) 1109 if (canSafelyExposeURL) {
778 return false; 1110 // 'KURL::strippedForUseAsReferrer()' dumps 'String()' for non-webby URLs.
779 } 1111 // It's better for developers if we return the origin of those URLs rather
780 return true; 1112 // than nothing.
781 } 1113 if (url.protocolIsInHTTPFamily())
782 1114 return url.strippedForUseAsReferrer();
783 bool ContentSecurityPolicy::allowRequest( 1115 }
784 WebURLRequest::RequestContext context, 1116 return SecurityOrigin::create(url)->toString();
785 const KURL& url, 1117 }
786 const String& nonce, 1118
787 const IntegrityMetadataSet& integrityMetadata, 1119 static void gatherSecurityPolicyViolationEventData(
788 ParserDisposition parserDisposition, 1120 SecurityPolicyViolationEventInit& init,
789 RedirectStatus redirectStatus, 1121 Document* document,
790 ReportingStatus reportingStatus) const { 1122 const String& directiveText,
791 if (integrityMetadata.isEmpty() && 1123 const String& effectiveDirective,
792 !allowRequestWithoutIntegrity(context, url, redirectStatus, 1124 const KURL& blockedURL,
793 reportingStatus)) 1125 const String& header,
1126 RedirectStatus redirectStatus,
1127 ContentSecurityPolicy::ViolationType violationType,
1128 int contextLine) {
1129 if (equalIgnoringCase(effectiveDirective,
1130 ContentSecurityPolicy::FrameAncestors)) {
1131 // If this load was blocked via 'frame-ancestors', then the URL of
1132 // |document| has not yet been initialized. In this case, we'll set both
1133 // 'documentURI' and 'blockedURI' to the blocked document's URL.
1134 init.setDocumentURI(blockedURL.getString());
1135 init.setBlockedURI(blockedURL.getString());
1136 } else {
1137 init.setDocumentURI(document->url().getString());
1138 switch (violationType) {
1139 case ContentSecurityPolicy::InlineViolation:
1140 init.setBlockedURI("inline");
1141 break;
1142 case ContentSecurityPolicy::EvalViolation:
1143 init.setBlockedURI("eval");
1144 break;
1145 case ContentSecurityPolicy::URLViolation:
1146 init.setBlockedURI(stripURLForUseInReport(
1147 document, blockedURL, redirectStatus, effectiveDirective));
1148 break;
1149 }
1150 }
1151 init.setReferrer(document->referrer());
1152 init.setViolatedDirective(directiveText);
1153 init.setEffectiveDirective(effectiveDirective);
1154 init.setOriginalPolicy(header);
1155 init.setSourceFile(String());
1156 init.setLineNumber(contextLine);
1157 init.setColumnNumber(0);
1158 init.setStatusCode(0);
1159
1160 if (!SecurityOrigin::isSecure(document->url()) && document->loader())
1161 init.setStatusCode(document->loader()->response().httpStatusCode());
1162
1163 std::unique_ptr<SourceLocation> location =
1164 SourceLocation::capture(document);
1165 if (location->lineNumber()) {
1166 KURL source = KURL(ParsedURLString, location->url());
1167 init.setSourceFile(stripURLForUseInReport(
1168 document, source, redirectStatus, effectiveDirective));
1169 init.setLineNumber(location->lineNumber());
1170 init.setColumnNumber(location->columnNumber());
1171 }
1172 }
1173
1174 void ContentSecurityPolicy::reportViolation(
1175 const String& directiveText,
1176 const String& effectiveDirective,
1177 const String& consoleMessage,
1178 const KURL& blockedURL,
1179 const Vector<String>& reportEndpoints,
1180 const String& header,
1181 ViolationType violationType,
1182 LocalFrame* contextFrame,
1183 RedirectStatus redirectStatus,
1184 int contextLine) {
1185 DCHECK(violationType == URLViolation || blockedURL.isEmpty());
1186
1187 // TODO(lukasza): Support sending reports from OOPIFs -
1188 // https://crbug.com/611232 (or move CSP child-src and frame-src checks to
1189 // the
1190 // browser process - see https://crbug.com/376522).
1191 if (!m_executionContext && !contextFrame) {
1192 DCHECK(equalIgnoringCase(effectiveDirective,
1193 ContentSecurityPolicy::ChildSrc) ||
1194 equalIgnoringCase(effectiveDirective,
1195 ContentSecurityPolicy::FrameSrc) ||
1196 equalIgnoringCase(effectiveDirective,
1197 ContentSecurityPolicy::PluginTypes));
1198 return;
1199 }
1200
1201 DCHECK((m_executionContext && !contextFrame) ||
1202 (equalIgnoringCase(effectiveDirective,
1203 ContentSecurityPolicy::FrameAncestors) &&
1204 contextFrame));
1205
1206 // FIXME: Support sending reports from worker.
1207 Document* document =
1208 contextFrame ? contextFrame->document() : this->document();
1209 if (!document)
1210 return;
1211
1212 SecurityPolicyViolationEventInit violationData;
1213 gatherSecurityPolicyViolationEventData(
1214 violationData, document, directiveText, effectiveDirective, blockedURL,
1215 header, redirectStatus, violationType, contextLine);
1216
1217 // TODO(mkwst): Obviously, we shouldn't hit this check, as extension-loaded
1218 // resources should be allowed regardless. We apparently do, however, so
1219 // we should at least stop spamming reporting endpoints. See
1220 // https://crbug.com/524356 for detail.
1221 if (!violationData.sourceFile().isEmpty() &&
1222 SchemeRegistry::schemeShouldBypassContentSecurityPolicy(
1223 KURL(ParsedURLString, violationData.sourceFile()).protocol()))
1224 return;
1225
1226 // We need to be careful here when deciding what information to send to the
1227 // report-uri. Currently, we send only the current document's URL and the
1228 // directive that was violated. The document's URL is safe to send because
1229 // it's the document itself that's requesting that it be sent. You could
1230 // make an argument that we shouldn't send HTTPS document URLs to HTTP
1231 // report-uris (for the same reasons that we supress the Referer in that
1232 // case), but the Referer is sent implicitly whereas this request is only
1233 // sent explicitly. As for which directive was violated, that's pretty
1234 // harmless information.
1235
1236 std::unique_ptr<JSONObject> cspReport = JSONObject::create();
1237 cspReport->setString("document-uri", violationData.documentURI());
1238 cspReport->setString("referrer", violationData.referrer());
1239 cspReport->setString("violated-directive",
1240 violationData.violatedDirective());
1241 cspReport->setString("effective-directive",
1242 violationData.effectiveDirective());
1243 cspReport->setString("original-policy", violationData.originalPolicy());
1244 cspReport->setString("blocked-uri", violationData.blockedURI());
1245 if (violationData.lineNumber())
1246 cspReport->setInteger("line-number", violationData.lineNumber());
1247 if (violationData.columnNumber())
1248 cspReport->setInteger("column-number", violationData.columnNumber());
1249 if (!violationData.sourceFile().isEmpty())
1250 cspReport->setString("source-file", violationData.sourceFile());
1251 cspReport->setInteger("status-code", violationData.statusCode());
1252
1253 std::unique_ptr<JSONObject> reportObject = JSONObject::create();
1254 reportObject->setObject("csp-report", std::move(cspReport));
1255 String stringifiedReport = reportObject->toJSONString();
1256
1257 if (!shouldSendViolationReport(stringifiedReport))
1258 return;
1259 didSendViolationReport(stringifiedReport);
1260
1261 RefPtr<EncodedFormData> report =
1262 EncodedFormData::create(stringifiedReport.utf8());
1263
1264 LocalFrame* frame = document->frame();
1265 if (!frame)
1266 return;
1267 frame->localDOMWindow()->enqueueDocumentEvent(
1268 SecurityPolicyViolationEvent::create(
1269 EventTypeNames::securitypolicyviolation, violationData));
1270
1271 for (const String& endpoint : reportEndpoints) {
1272 // If we have a context frame we're dealing with 'frame-ancestors' and we
1273 // don't have our own execution context. Use the frame's document to
1274 // complete the endpoint URL, overriding its URL with the blocked
1275 // document's
1276 // URL.
1277 DCHECK(!contextFrame || !m_executionContext);
1278 DCHECK(!contextFrame ||
1279 equalIgnoringCase(effectiveDirective, FrameAncestors));
1280 KURL url =
1281 contextFrame
1282 ? frame->document()->completeURLWithOverride(endpoint, blockedURL)
1283 : completeURL(endpoint);
1284 PingLoader::sendViolationReport(
1285 frame, url, report, PingLoader::ContentSecurityPolicyViolationReport);
1286 }
1287 }
1288
1289 void ContentSecurityPolicy::reportMixedContent(
1290 const KURL& mixedURL,
1291 RedirectStatus redirectStatus) {
1292 for (const auto& policy : m_policies)
1293 policy->reportMixedContent(mixedURL, redirectStatus);
1294 }
1295
1296 void ContentSecurityPolicy::reportInvalidReferrer(
1297 const String& invalidValue) {
1298 logToConsole(
1299 "The 'referrer' Content Security Policy directive has the invalid "
1300 "value "
1301 "\"" +
1302 invalidValue +
1303 "\". Valid values are \"no-referrer\", \"no-referrer-when-downgrade\", "
1304 "\"origin\", \"origin-when-cross-origin\", and \"unsafe-url\".");
1305 }
1306
1307 void ContentSecurityPolicy::reportReportOnlyInMeta(const String& header) {
1308 logToConsole(
1309 "The report-only Content Security Policy '" + header +
1310 "' was delivered via a <meta> element, which is disallowed. The "
1311 "policy has been ignored.");
1312 }
1313
1314 void ContentSecurityPolicy::reportMetaOutsideHead(const String& header) {
1315 logToConsole("The Content Security Policy '" + header +
1316 "' was delivered via a <meta> element outside the document's "
1317 "<head>, which is disallowed. The policy has been ignored.");
1318 }
1319
1320 void ContentSecurityPolicy::reportValueForEmptyDirective(
1321 const String& name,
1322 const String& value) {
1323 logToConsole("The Content Security Policy directive '" + name +
1324 "' should be empty, but was delivered with a value of '" +
1325 value +
1326 "'. The directive has been applied, and the value ignored.");
1327 }
1328
1329 void ContentSecurityPolicy::reportInvalidInReportOnly(const String& name) {
1330 logToConsole("The Content Security Policy directive '" + name +
1331 "' is ignored when delivered in a report-only policy.");
1332 }
1333
1334 void ContentSecurityPolicy::reportInvalidDirectiveInMeta(
1335 const String& directive) {
1336 logToConsole(
1337 "Content Security Policies delivered via a <meta> element may not "
1338 "contain the " +
1339 directive + " directive.");
1340 }
1341
1342 void ContentSecurityPolicy::reportUnsupportedDirective(const String& name) {
1343 DEFINE_STATIC_LOCAL(String, allow, ("allow"));
1344 DEFINE_STATIC_LOCAL(String, options, ("options"));
1345 DEFINE_STATIC_LOCAL(String, policyURI, ("policy-uri"));
1346 DEFINE_STATIC_LOCAL(String, allowMessage,
1347 ("The 'allow' directive has been replaced with "
1348 "'default-src'. Please use "
1349 "that directive instead, as 'allow' has no effect."));
1350 DEFINE_STATIC_LOCAL(
1351 String, optionsMessage,
1352 ("The 'options' directive has been replaced with 'unsafe-inline' and "
1353 "'unsafe-eval' source expressions for the 'script-src' and "
1354 "'style-src' "
1355 "directives. Please use those directives instead, as 'options' has no "
1356 "effect."));
1357 DEFINE_STATIC_LOCAL(String, policyURIMessage,
1358 ("The 'policy-uri' directive has been removed from the "
1359 "specification. Please specify a complete policy via "
1360 "the Content-Security-Policy header."));
1361
1362 String message =
1363 "Unrecognized Content-Security-Policy directive '" + name + "'.\n";
1364 MessageLevel level = ErrorMessageLevel;
1365 if (equalIgnoringCase(name, allow)) {
1366 message = allowMessage;
1367 } else if (equalIgnoringCase(name, options)) {
1368 message = optionsMessage;
1369 } else if (equalIgnoringCase(name, policyURI)) {
1370 message = policyURIMessage;
1371 } else if (isDirectiveName(name)) {
1372 message = "The Content-Security-Policy directive '" + name +
1373 "' is implemented behind a flag which is currently disabled.\n";
1374 level = InfoMessageLevel;
1375 }
1376
1377 logToConsole(message, level);
1378 }
1379
1380 void ContentSecurityPolicy::reportDirectiveAsSourceExpression(
1381 const String& directiveName,
1382 const String& sourceExpression) {
1383 String message = "The Content Security Policy directive '" + directiveName +
1384 "' contains '" + sourceExpression +
1385 "' as a source expression. Did you mean '" +
1386 directiveName + " ...; " + sourceExpression +
1387 "...' (note the semicolon)?";
1388 logToConsole(message);
1389 }
1390
1391 void ContentSecurityPolicy::reportDuplicateDirective(const String& name) {
1392 String message = "Ignoring duplicate Content-Security-Policy directive '" +
1393 name + "'.\n";
1394 logToConsole(message);
1395 }
1396
1397 void ContentSecurityPolicy::reportInvalidPluginTypes(
1398 const String& pluginType) {
1399 String message;
1400 if (pluginType.isNull()) {
1401 message =
1402 "'plugin-types' Content Security Policy directive is empty; all "
1403 "plugins will be blocked.\n";
1404 } else if (pluginType == "'none'") {
1405 message =
1406 "Invalid plugin type in 'plugin-types' Content Security Policy "
1407 "directive: '" +
1408 pluginType +
1409 "'. Did you mean to set the object-src directive to 'none'?\n";
1410 } else {
1411 message =
1412 "Invalid plugin type in 'plugin-types' Content Security Policy "
1413 "directive: '" +
1414 pluginType + "'.\n";
1415 }
1416 logToConsole(message);
1417 }
1418
1419 void ContentSecurityPolicy::reportInvalidSandboxFlags(
1420 const String& invalidFlags) {
1421 logToConsole(
1422 "Error while parsing the 'sandbox' Content Security Policy "
1423 "directive: " +
1424 invalidFlags);
1425 }
1426
1427 void ContentSecurityPolicy::reportInvalidReflectedXSS(
1428 const String& invalidValue) {
1429 logToConsole(
1430 "The 'reflected-xss' Content Security Policy directive has the invalid "
1431 "value \"" +
1432 invalidValue +
1433 "\". Valid values are \"allow\", \"filter\", and \"block\".");
1434 }
1435
1436 void ContentSecurityPolicy::reportInvalidRequireSRIForTokens(
1437 const String& invalidTokens) {
1438 logToConsole(
1439 "Error while parsing the 'require-sri-for' Content Security Policy "
1440 "directive: " +
1441 invalidTokens);
1442 }
1443
1444 void ContentSecurityPolicy::reportInvalidDirectiveValueCharacter(
1445 const String& directiveName,
1446 const String& value) {
1447 String message =
1448 "The value for Content Security Policy directive '" + directiveName +
1449 "' contains an invalid character: '" + value +
1450 "'. Non-whitespace characters outside ASCII 0x21-0x7E must "
1451 "be percent-encoded, as described in RFC 3986, section 2.1: "
1452 "http://tools.ietf.org/html/rfc3986#section-2.1.";
1453 logToConsole(message);
1454 }
1455
1456 void ContentSecurityPolicy::reportInvalidPathCharacter(
1457 const String& directiveName,
1458 const String& value,
1459 const char invalidChar) {
1460 DCHECK(invalidChar == '#' || invalidChar == '?');
1461
1462 String ignoring =
1463 "The fragment identifier, including the '#', will be ignored.";
1464 if (invalidChar == '?')
1465 ignoring = "The query component, including the '?', will be ignored.";
1466 String message = "The source list for Content Security Policy directive '" +
1467 directiveName +
1468 "' contains a source with an invalid path: '" + value +
1469 "'. " + ignoring;
1470 logToConsole(message);
1471 }
1472
1473 void ContentSecurityPolicy::reportInvalidSourceExpression(
1474 const String& directiveName,
1475 const String& source) {
1476 String message = "The source list for Content Security Policy directive '" +
1477 directiveName + "' contains an invalid source: '" +
1478 source + "'. It will be ignored.";
1479 if (equalIgnoringCase(source, "'none'")) {
1480 message = message +
1481 " Note that 'none' has no effect unless it is the only "
1482 "expression in the source list.";
1483 }
1484 logToConsole(message);
1485 }
1486
1487 void ContentSecurityPolicy::reportMissingReportURI(const String& policy) {
1488 logToConsole("The Content Security Policy '" + policy +
1489 "' was delivered in report-only mode, but does not specify a "
1490 "'report-uri'; the policy will have no effect. Please either "
1491 "add a 'report-uri' directive, or deliver the policy via the "
1492 "'Content-Security-Policy' header.");
1493 }
1494
1495 void ContentSecurityPolicy::logToConsole(const String& message,
1496 MessageLevel level) {
1497 logToConsole(ConsoleMessage::create(SecurityMessageSource, level, message));
1498 }
1499
1500 void ContentSecurityPolicy::logToConsole(ConsoleMessage* consoleMessage,
1501 LocalFrame* frame) {
1502 if (frame)
1503 frame->document()->addConsoleMessage(consoleMessage);
1504 else if (m_executionContext)
1505 m_executionContext->addConsoleMessage(consoleMessage);
1506 else
1507 m_consoleMessages.append(consoleMessage);
1508 }
1509
1510 void ContentSecurityPolicy::reportBlockedScriptExecutionToInspector(
1511 const String& directiveText) const {
1512 InspectorInstrumentation::scriptExecutionBlockedByCSP(m_executionContext,
1513 directiveText);
1514 }
1515
1516 bool ContentSecurityPolicy::experimentalFeaturesEnabled() const {
1517 return RuntimeEnabledFeatures::
1518 experimentalContentSecurityPolicyFeaturesEnabled();
1519 }
1520
1521 bool ContentSecurityPolicy::shouldSendCSPHeader(Resource::Type type) const {
1522 for (const auto& policy : m_policies) {
1523 if (policy->shouldSendCSPHeader(type))
1524 return true;
1525 }
794 return false; 1526 return false;
795 1527 }
796 switch (context) { 1528
797 case WebURLRequest::RequestContextAudio: 1529 bool ContentSecurityPolicy::urlMatchesSelf(const KURL& url) const {
798 case WebURLRequest::RequestContextTrack: 1530 return m_selfSource->matches(url, RedirectStatus::NoRedirect);
799 case WebURLRequest::RequestContextVideo: 1531 }
800 return allowMediaFromSource(url, redirectStatus, reportingStatus); 1532
801 case WebURLRequest::RequestContextBeacon: 1533 bool ContentSecurityPolicy::protocolMatchesSelf(const KURL& url) const {
802 case WebURLRequest::RequestContextEventSource: 1534 if (equalIgnoringCase("http", m_selfProtocol))
803 case WebURLRequest::RequestContextFetch: 1535 return url.protocolIsInHTTPFamily();
804 case WebURLRequest::RequestContextXMLHttpRequest: 1536 return equalIgnoringCase(url.protocol(), m_selfProtocol);
805 return allowConnectToSource(url, redirectStatus, reportingStatus); 1537 }
806 case WebURLRequest::RequestContextEmbed: 1538
807 case WebURLRequest::RequestContextObject: 1539 bool ContentSecurityPolicy::selfMatchesInnerURL() const {
808 return allowObjectFromSource(url, redirectStatus, reportingStatus); 1540 // Due to backwards-compatibility concerns, we allow 'self' to match blob
809 case WebURLRequest::RequestContextFavicon: 1541 // and
810 case WebURLRequest::RequestContextImage: 1542 // filesystem URLs if we're in a context that bypasses Content Security
811 case WebURLRequest::RequestContextImageSet: 1543 // Policy
812 return allowImageFromSource(url, redirectStatus, reportingStatus); 1544 // in the main world.
813 case WebURLRequest::RequestContextFont: 1545 //
814 return allowFontFromSource(url, redirectStatus, reportingStatus); 1546 // TODO(mkwst): Revisit this once embedders have an opportunity to update
815 case WebURLRequest::RequestContextForm: 1547 // their extension models.
816 return allowFormAction(url, redirectStatus, reportingStatus); 1548 return m_executionContext &&
817 case WebURLRequest::RequestContextFrame: 1549 SchemeRegistry::schemeShouldBypassContentSecurityPolicy(
818 case WebURLRequest::RequestContextIframe: 1550 m_executionContext->getSecurityOrigin()->protocol());
819 return allowChildFrameFromSource(url, redirectStatus, reportingStatus); 1551 }
820 case WebURLRequest::RequestContextImport: 1552
821 case WebURLRequest::RequestContextScript: 1553 bool ContentSecurityPolicy::shouldBypassMainWorld(
822 return allowScriptFromSource(url, nonce, parserDisposition, 1554 const ExecutionContext* context) {
823 redirectStatus, reportingStatus); 1555 if (context && context->isDocument()) {
824 case WebURLRequest::RequestContextXSLT: 1556 const Document* document = toDocument(context);
825 return allowScriptFromSource(url, nonce, parserDisposition, 1557 if (document->frame())
826 redirectStatus, reportingStatus); 1558 return document->frame()->script().shouldBypassMainWorldCSP();
827 case WebURLRequest::RequestContextManifest: 1559 }
828 return allowManifestFromSource(url, redirectStatus, reportingStatus); 1560 return false;
829 case WebURLRequest::RequestContextServiceWorker: 1561 }
830 case WebURLRequest::RequestContextSharedWorker: 1562
831 case WebURLRequest::RequestContextWorker: 1563 bool ContentSecurityPolicy::shouldSendViolationReport(
832 return allowWorkerContextFromSource(url, redirectStatus, reportingStatus); 1564 const String& report) const {
833 case WebURLRequest::RequestContextStyle: 1565 // Collisions have no security impact, so we can save space by storing only
834 return allowStyleFromSource(url, nonce, redirectStatus, reportingStatus); 1566 // the string's hash rather than the whole report.
835 case WebURLRequest::RequestContextCSPReport: 1567 return !m_violationReportsSent.contains(report.impl()->hash());
836 case WebURLRequest::RequestContextDownload: 1568 }
837 case WebURLRequest::RequestContextHyperlink: 1569
838 case WebURLRequest::RequestContextInternal: 1570 void ContentSecurityPolicy::didSendViolationReport(const String& report) {
839 case WebURLRequest::RequestContextLocation: 1571 m_violationReportsSent.add(report.impl()->hash());
840 case WebURLRequest::RequestContextPing: 1572 }
841 case WebURLRequest::RequestContextPlugin:
842 case WebURLRequest::RequestContextPrefetch:
843 case WebURLRequest::RequestContextSubresource:
844 case WebURLRequest::RequestContextUnspecified:
845 return true;
846 }
847 ASSERT_NOT_REACHED();
848 return true;
849 }
850
851 void ContentSecurityPolicy::usesScriptHashAlgorithms(uint8_t algorithms) {
852 m_scriptHashAlgorithmsUsed |= algorithms;
853 }
854
855 void ContentSecurityPolicy::usesStyleHashAlgorithms(uint8_t algorithms) {
856 m_styleHashAlgorithmsUsed |= algorithms;
857 }
858
859 bool ContentSecurityPolicy::allowObjectFromSource(
860 const KURL& url,
861 RedirectStatus redirectStatus,
862 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
863 return isAllowedByAllWithURL<&CSPDirectiveList::allowObjectFromSource>(
864 m_policies, url, redirectStatus, reportingStatus);
865 }
866
867 bool ContentSecurityPolicy::allowChildFrameFromSource(
868 const KURL& url,
869 RedirectStatus redirectStatus,
870 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
871 return isAllowedByAllWithURL<&CSPDirectiveList::allowChildFrameFromSource>(
872 m_policies, url, redirectStatus, reportingStatus);
873 }
874
875 bool ContentSecurityPolicy::allowImageFromSource(
876 const KURL& url,
877 RedirectStatus redirectStatus,
878 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
879 if (SchemeRegistry::schemeShouldBypassContentSecurityPolicy(
880 url.protocol(), SchemeRegistry::PolicyAreaImage))
881 return true;
882 return isAllowedByAllWithURL<&CSPDirectiveList::allowImageFromSource>(
883 m_policies, url, redirectStatus, reportingStatus);
884 }
885
886 bool ContentSecurityPolicy::allowStyleFromSource(
887 const KURL& url,
888 const String& nonce,
889 RedirectStatus redirectStatus,
890 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
891 if (SchemeRegistry::schemeShouldBypassContentSecurityPolicy(
892 url.protocol(), SchemeRegistry::PolicyAreaStyle))
893 return true;
894 return isAllowedByAllWithURLWithNonce<
895 &CSPDirectiveList::allowStyleFromSource>(m_policies, url, nonce,
896 redirectStatus, reportingStatus);
897 }
898
899 bool ContentSecurityPolicy::allowFontFromSource(
900 const KURL& url,
901 RedirectStatus redirectStatus,
902 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
903 return isAllowedByAllWithURL<&CSPDirectiveList::allowFontFromSource>(
904 m_policies, url, redirectStatus, reportingStatus);
905 }
906
907 bool ContentSecurityPolicy::allowMediaFromSource(
908 const KURL& url,
909 RedirectStatus redirectStatus,
910 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
911 return isAllowedByAllWithURL<&CSPDirectiveList::allowMediaFromSource>(
912 m_policies, url, redirectStatus, reportingStatus);
913 }
914
915 bool ContentSecurityPolicy::allowConnectToSource(
916 const KURL& url,
917 RedirectStatus redirectStatus,
918 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
919 return isAllowedByAllWithURL<&CSPDirectiveList::allowConnectToSource>(
920 m_policies, url, redirectStatus, reportingStatus);
921 }
922
923 bool ContentSecurityPolicy::allowFormAction(
924 const KURL& url,
925 RedirectStatus redirectStatus,
926 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
927 return isAllowedByAllWithURL<&CSPDirectiveList::allowFormAction>(
928 m_policies, url, redirectStatus, reportingStatus);
929 }
930
931 bool ContentSecurityPolicy::allowBaseURI(
932 const KURL& url,
933 RedirectStatus redirectStatus,
934 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
935 return isAllowedByAllWithURL<&CSPDirectiveList::allowBaseURI>(
936 m_policies, url, redirectStatus, reportingStatus);
937 }
938
939 bool ContentSecurityPolicy::allowWorkerContextFromSource(
940 const KURL& url,
941 RedirectStatus redirectStatus,
942 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
943 // CSP 1.1 moves workers from 'script-src' to the new 'child-src'. Measure the
944 // impact of this backwards-incompatible change.
945 if (Document* document = this->document()) {
946 UseCounter::count(*document, UseCounter::WorkerSubjectToCSP);
947 if (isAllowedByAllWithURL<&CSPDirectiveList::allowChildContextFromSource>(
948 m_policies, url, redirectStatus, SuppressReport) &&
949 !isAllowedByAllWithURLNonceAndParser<
950 &CSPDirectiveList::allowScriptFromSource>(
951 m_policies, url, AtomicString(), NotParserInserted, redirectStatus,
952 SuppressReport)) {
953 UseCounter::count(*document,
954 UseCounter::WorkerAllowedByChildBlockedByScript);
955 }
956 }
957
958 return isAllowedByAllWithURL<&CSPDirectiveList::allowChildContextFromSource>(
959 m_policies, url, redirectStatus, reportingStatus);
960 }
961
962 bool ContentSecurityPolicy::allowManifestFromSource(
963 const KURL& url,
964 RedirectStatus redirectStatus,
965 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
966 return isAllowedByAllWithURL<&CSPDirectiveList::allowManifestFromSource>(
967 m_policies, url, redirectStatus, reportingStatus);
968 }
969
970 bool ContentSecurityPolicy::allowAncestors(
971 LocalFrame* frame,
972 const KURL& url,
973 ContentSecurityPolicy::ReportingStatus reportingStatus) const {
974 return isAllowedByAllWithFrame<&CSPDirectiveList::allowAncestors>(
975 m_policies, frame, url, reportingStatus);
976 }
977
978 bool ContentSecurityPolicy::isFrameAncestorsEnforced() const {
979 for (const auto& policy : m_policies) {
980 if (policy->isFrameAncestorsEnforced())
981 return true;
982 }
983 return false;
984 }
985
986 bool ContentSecurityPolicy::isActive() const {
987 return !m_policies.isEmpty();
988 }
989
990 ReflectedXSSDisposition ContentSecurityPolicy::getReflectedXSSDisposition()
991 const {
992 ReflectedXSSDisposition disposition = ReflectedXSSUnset;
993 for (const auto& policy : m_policies) {
994 if (policy->getReflectedXSSDisposition() > disposition)
995 disposition = std::max(disposition, policy->getReflectedXSSDisposition());
996 }
997 return disposition;
998 }
999
1000 bool ContentSecurityPolicy::didSetReferrerPolicy() const {
1001 for (const auto& policy : m_policies) {
1002 if (policy->didSetReferrerPolicy())
1003 return true;
1004 }
1005 return false;
1006 }
1007
1008 const KURL ContentSecurityPolicy::url() const {
1009 return m_executionContext->contextURL();
1010 }
1011
1012 KURL ContentSecurityPolicy::completeURL(const String& url) const {
1013 return m_executionContext->contextCompleteURL(url);
1014 }
1015
1016 void ContentSecurityPolicy::enforceSandboxFlags(SandboxFlags mask) {
1017 m_sandboxMask |= mask;
1018 }
1019
1020 void ContentSecurityPolicy::treatAsPublicAddress() {
1021 if (!RuntimeEnabledFeatures::corsRFC1918Enabled())
1022 return;
1023 m_treatAsPublicAddress = true;
1024 }
1025
1026 void ContentSecurityPolicy::enforceStrictMixedContentChecking() {
1027 m_insecureRequestPolicy |= kBlockAllMixedContent;
1028 }
1029
1030 void ContentSecurityPolicy::upgradeInsecureRequests() {
1031 m_insecureRequestPolicy |= kUpgradeInsecureRequests;
1032 }
1033
1034 static String stripURLForUseInReport(Document* document,
1035 const KURL& url,
1036 RedirectStatus redirectStatus,
1037 const String& effectiveDirective) {
1038 if (!url.isValid())
1039 return String();
1040 if (!url.isHierarchical() || url.protocolIs("file"))
1041 return url.protocol();
1042
1043 // Until we're more careful about the way we deal with navigations in frames
1044 // (and, by extension, in plugin documents), strip cross-origin 'frame-src'
1045 // and 'object-src' violations down to an origin. https://crbug.com/633306
1046 bool canSafelyExposeURL =
1047 document->getSecurityOrigin()->canRequest(url) ||
1048 (redirectStatus == RedirectStatus::NoRedirect &&
1049 !equalIgnoringCase(effectiveDirective,
1050 ContentSecurityPolicy::FrameSrc) &&
1051 !equalIgnoringCase(effectiveDirective,
1052 ContentSecurityPolicy::ObjectSrc));
1053
1054 if (canSafelyExposeURL) {
1055 // 'KURL::strippedForUseAsReferrer()' dumps 'String()' for non-webby URLs.
1056 // It's better for developers if we return the origin of those URLs rather
1057 // than nothing.
1058 if (url.protocolIsInHTTPFamily())
1059 return url.strippedForUseAsReferrer();
1060 }
1061 return SecurityOrigin::create(url)->toString();
1062 }
1063
1064 static void gatherSecurityPolicyViolationEventData(
1065 SecurityPolicyViolationEventInit& init,
1066 Document* document,
1067 const String& directiveText,
1068 const String& effectiveDirective,
1069 const KURL& blockedURL,
1070 const String& header,
1071 RedirectStatus redirectStatus,
1072 ContentSecurityPolicy::ViolationType violationType,
1073 int contextLine) {
1074 if (equalIgnoringCase(effectiveDirective,
1075 ContentSecurityPolicy::FrameAncestors)) {
1076 // If this load was blocked via 'frame-ancestors', then the URL of
1077 // |document| has not yet been initialized. In this case, we'll set both
1078 // 'documentURI' and 'blockedURI' to the blocked document's URL.
1079 init.setDocumentURI(blockedURL.getString());
1080 init.setBlockedURI(blockedURL.getString());
1081 } else {
1082 init.setDocumentURI(document->url().getString());
1083 switch (violationType) {
1084 case ContentSecurityPolicy::InlineViolation:
1085 init.setBlockedURI("inline");
1086 break;
1087 case ContentSecurityPolicy::EvalViolation:
1088 init.setBlockedURI("eval");
1089 break;
1090 case ContentSecurityPolicy::URLViolation:
1091 init.setBlockedURI(stripURLForUseInReport(
1092 document, blockedURL, redirectStatus, effectiveDirective));
1093 break;
1094 }
1095 }
1096 init.setReferrer(document->referrer());
1097 init.setViolatedDirective(directiveText);
1098 init.setEffectiveDirective(effectiveDirective);
1099 init.setOriginalPolicy(header);
1100 init.setSourceFile(String());
1101 init.setLineNumber(contextLine);
1102 init.setColumnNumber(0);
1103 init.setStatusCode(0);
1104
1105 if (!SecurityOrigin::isSecure(document->url()) && document->loader())
1106 init.setStatusCode(document->loader()->response().httpStatusCode());
1107
1108 std::unique_ptr<SourceLocation> location = SourceLocation::capture(document);
1109 if (location->lineNumber()) {
1110 KURL source = KURL(ParsedURLString, location->url());
1111 init.setSourceFile(stripURLForUseInReport(document, source, redirectStatus,
1112 effectiveDirective));
1113 init.setLineNumber(location->lineNumber());
1114 init.setColumnNumber(location->columnNumber());
1115 }
1116 }
1117
1118 void ContentSecurityPolicy::reportViolation(
1119 const String& directiveText,
1120 const String& effectiveDirective,
1121 const String& consoleMessage,
1122 const KURL& blockedURL,
1123 const Vector<String>& reportEndpoints,
1124 const String& header,
1125 ViolationType violationType,
1126 LocalFrame* contextFrame,
1127 RedirectStatus redirectStatus,
1128 int contextLine) {
1129 ASSERT(violationType == URLViolation || blockedURL.isEmpty());
1130
1131 // TODO(lukasza): Support sending reports from OOPIFs -
1132 // https://crbug.com/611232 (or move CSP child-src and frame-src checks to the
1133 // browser process - see https://crbug.com/376522).
1134 if (!m_executionContext && !contextFrame) {
1135 DCHECK(equalIgnoringCase(effectiveDirective,
1136 ContentSecurityPolicy::ChildSrc) ||
1137 equalIgnoringCase(effectiveDirective,
1138 ContentSecurityPolicy::FrameSrc) ||
1139 equalIgnoringCase(effectiveDirective,
1140 ContentSecurityPolicy::PluginTypes));
1141 return;
1142 }
1143
1144 ASSERT((m_executionContext && !contextFrame) ||
1145 (equalIgnoringCase(effectiveDirective,
1146 ContentSecurityPolicy::FrameAncestors) &&
1147 contextFrame));
1148
1149 // FIXME: Support sending reports from worker.
1150 Document* document =
1151 contextFrame ? contextFrame->document() : this->document();
1152 if (!document)
1153 return;
1154
1155 SecurityPolicyViolationEventInit violationData;
1156 gatherSecurityPolicyViolationEventData(
1157 violationData, document, directiveText, effectiveDirective, blockedURL,
1158 header, redirectStatus, violationType, contextLine);
1159
1160 // TODO(mkwst): Obviously, we shouldn't hit this check, as extension-loaded
1161 // resources should be allowed regardless. We apparently do, however, so
1162 // we should at least stop spamming reporting endpoints. See
1163 // https://crbug.com/524356 for detail.
1164 if (!violationData.sourceFile().isEmpty() &&
1165 SchemeRegistry::schemeShouldBypassContentSecurityPolicy(
1166 KURL(ParsedURLString, violationData.sourceFile()).protocol()))
1167 return;
1168
1169 // We need to be careful here when deciding what information to send to the
1170 // report-uri. Currently, we send only the current document's URL and the
1171 // directive that was violated. The document's URL is safe to send because
1172 // it's the document itself that's requesting that it be sent. You could
1173 // make an argument that we shouldn't send HTTPS document URLs to HTTP
1174 // report-uris (for the same reasons that we supress the Referer in that
1175 // case), but the Referer is sent implicitly whereas this request is only
1176 // sent explicitly. As for which directive was violated, that's pretty
1177 // harmless information.
1178
1179 std::unique_ptr<JSONObject> cspReport = JSONObject::create();
1180 cspReport->setString("document-uri", violationData.documentURI());
1181 cspReport->setString("referrer", violationData.referrer());
1182 cspReport->setString("violated-directive", violationData.violatedDirective());
1183 cspReport->setString("effective-directive",
1184 violationData.effectiveDirective());
1185 cspReport->setString("original-policy", violationData.originalPolicy());
1186 cspReport->setString("blocked-uri", violationData.blockedURI());
1187 if (violationData.lineNumber())
1188 cspReport->setInteger("line-number", violationData.lineNumber());
1189 if (violationData.columnNumber())
1190 cspReport->setInteger("column-number", violationData.columnNumber());
1191 if (!violationData.sourceFile().isEmpty())
1192 cspReport->setString("source-file", violationData.sourceFile());
1193 cspReport->setInteger("status-code", violationData.statusCode());
1194
1195 std::unique_ptr<JSONObject> reportObject = JSONObject::create();
1196 reportObject->setObject("csp-report", std::move(cspReport));
1197 String stringifiedReport = reportObject->toJSONString();
1198
1199 if (!shouldSendViolationReport(stringifiedReport))
1200 return;
1201 didSendViolationReport(stringifiedReport);
1202
1203 RefPtr<EncodedFormData> report =
1204 EncodedFormData::create(stringifiedReport.utf8());
1205
1206 LocalFrame* frame = document->frame();
1207 if (!frame)
1208 return;
1209 frame->localDOMWindow()->enqueueDocumentEvent(
1210 SecurityPolicyViolationEvent::create(
1211 EventTypeNames::securitypolicyviolation, violationData));
1212
1213 for (const String& endpoint : reportEndpoints) {
1214 // If we have a context frame we're dealing with 'frame-ancestors' and we
1215 // don't have our own execution context. Use the frame's document to
1216 // complete the endpoint URL, overriding its URL with the blocked document's
1217 // URL.
1218 DCHECK(!contextFrame || !m_executionContext);
1219 DCHECK(!contextFrame ||
1220 equalIgnoringCase(effectiveDirective, FrameAncestors));
1221 KURL url =
1222 contextFrame
1223 ? frame->document()->completeURLWithOverride(endpoint, blockedURL)
1224 : completeURL(endpoint);
1225 PingLoader::sendViolationReport(
1226 frame, url, report, PingLoader::ContentSecurityPolicyViolationReport);
1227 }
1228 }
1229
1230 void ContentSecurityPolicy::reportMixedContent(const KURL& mixedURL,
1231 RedirectStatus redirectStatus) {
1232 for (const auto& policy : m_policies)
1233 policy->reportMixedContent(mixedURL, redirectStatus);
1234 }
1235
1236 void ContentSecurityPolicy::reportInvalidReferrer(const String& invalidValue) {
1237 logToConsole(
1238 "The 'referrer' Content Security Policy directive has the invalid value "
1239 "\"" +
1240 invalidValue +
1241 "\". Valid values are \"no-referrer\", \"no-referrer-when-downgrade\", "
1242 "\"origin\", \"origin-when-cross-origin\", and \"unsafe-url\".");
1243 }
1244
1245 void ContentSecurityPolicy::reportReportOnlyInMeta(const String& header) {
1246 logToConsole("The report-only Content Security Policy '" + header +
1247 "' was delivered via a <meta> element, which is disallowed. The "
1248 "policy has been ignored.");
1249 }
1250
1251 void ContentSecurityPolicy::reportMetaOutsideHead(const String& header) {
1252 logToConsole("The Content Security Policy '" + header +
1253 "' was delivered via a <meta> element outside the document's "
1254 "<head>, which is disallowed. The policy has been ignored.");
1255 }
1256
1257 void ContentSecurityPolicy::reportValueForEmptyDirective(const String& name,
1258 const String& value) {
1259 logToConsole("The Content Security Policy directive '" + name +
1260 "' should be empty, but was delivered with a value of '" +
1261 value +
1262 "'. The directive has been applied, and the value ignored.");
1263 }
1264
1265 void ContentSecurityPolicy::reportInvalidInReportOnly(const String& name) {
1266 logToConsole("The Content Security Policy directive '" + name +
1267 "' is ignored when delivered in a report-only policy.");
1268 }
1269
1270 void ContentSecurityPolicy::reportInvalidDirectiveInMeta(
1271 const String& directive) {
1272 logToConsole(
1273 "Content Security Policies delivered via a <meta> element may not "
1274 "contain the " +
1275 directive + " directive.");
1276 }
1277
1278 void ContentSecurityPolicy::reportUnsupportedDirective(const String& name) {
1279 DEFINE_STATIC_LOCAL(String, allow, ("allow"));
1280 DEFINE_STATIC_LOCAL(String, options, ("options"));
1281 DEFINE_STATIC_LOCAL(String, policyURI, ("policy-uri"));
1282 DEFINE_STATIC_LOCAL(
1283 String, allowMessage,
1284 ("The 'allow' directive has been replaced with 'default-src'. Please use "
1285 "that directive instead, as 'allow' has no effect."));
1286 DEFINE_STATIC_LOCAL(
1287 String, optionsMessage,
1288 ("The 'options' directive has been replaced with 'unsafe-inline' and "
1289 "'unsafe-eval' source expressions for the 'script-src' and 'style-src' "
1290 "directives. Please use those directives instead, as 'options' has no "
1291 "effect."));
1292 DEFINE_STATIC_LOCAL(String, policyURIMessage,
1293 ("The 'policy-uri' directive has been removed from the "
1294 "specification. Please specify a complete policy via "
1295 "the Content-Security-Policy header."));
1296
1297 String message =
1298 "Unrecognized Content-Security-Policy directive '" + name + "'.\n";
1299 MessageLevel level = ErrorMessageLevel;
1300 if (equalIgnoringCase(name, allow)) {
1301 message = allowMessage;
1302 } else if (equalIgnoringCase(name, options)) {
1303 message = optionsMessage;
1304 } else if (equalIgnoringCase(name, policyURI)) {
1305 message = policyURIMessage;
1306 } else if (isDirectiveName(name)) {
1307 message = "The Content-Security-Policy directive '" + name +
1308 "' is implemented behind a flag which is currently disabled.\n";
1309 level = InfoMessageLevel;
1310 }
1311
1312 logToConsole(message, level);
1313 }
1314
1315 void ContentSecurityPolicy::reportDirectiveAsSourceExpression(
1316 const String& directiveName,
1317 const String& sourceExpression) {
1318 String message = "The Content Security Policy directive '" + directiveName +
1319 "' contains '" + sourceExpression +
1320 "' as a source expression. Did you mean '" + directiveName +
1321 " ...; " + sourceExpression + "...' (note the semicolon)?";
1322 logToConsole(message);
1323 }
1324
1325 void ContentSecurityPolicy::reportDuplicateDirective(const String& name) {
1326 String message =
1327 "Ignoring duplicate Content-Security-Policy directive '" + name + "'.\n";
1328 logToConsole(message);
1329 }
1330
1331 void ContentSecurityPolicy::reportInvalidPluginTypes(const String& pluginType) {
1332 String message;
1333 if (pluginType.isNull())
1334 message =
1335 "'plugin-types' Content Security Policy directive is empty; all "
1336 "plugins will be blocked.\n";
1337 else if (pluginType == "'none'")
1338 message =
1339 "Invalid plugin type in 'plugin-types' Content Security Policy "
1340 "directive: '" +
1341 pluginType +
1342 "'. Did you mean to set the object-src directive to 'none'?\n";
1343 else
1344 message =
1345 "Invalid plugin type in 'plugin-types' Content Security Policy "
1346 "directive: '" +
1347 pluginType + "'.\n";
1348 logToConsole(message);
1349 }
1350
1351 void ContentSecurityPolicy::reportInvalidSandboxFlags(
1352 const String& invalidFlags) {
1353 logToConsole(
1354 "Error while parsing the 'sandbox' Content Security Policy directive: " +
1355 invalidFlags);
1356 }
1357
1358 void ContentSecurityPolicy::reportInvalidReflectedXSS(
1359 const String& invalidValue) {
1360 logToConsole(
1361 "The 'reflected-xss' Content Security Policy directive has the invalid "
1362 "value \"" +
1363 invalidValue +
1364 "\". Valid values are \"allow\", \"filter\", and \"block\".");
1365 }
1366
1367 void ContentSecurityPolicy::reportInvalidRequireSRIForTokens(
1368 const String& invalidTokens) {
1369 logToConsole(
1370 "Error while parsing the 'require-sri-for' Content Security Policy "
1371 "directive: " +
1372 invalidTokens);
1373 }
1374
1375 void ContentSecurityPolicy::reportInvalidDirectiveValueCharacter(
1376 const String& directiveName,
1377 const String& value) {
1378 String message = "The value for Content Security Policy directive '" +
1379 directiveName + "' contains an invalid character: '" +
1380 value +
1381 "'. Non-whitespace characters outside ASCII 0x21-0x7E must "
1382 "be percent-encoded, as described in RFC 3986, section 2.1: "
1383 "http://tools.ietf.org/html/rfc3986#section-2.1.";
1384 logToConsole(message);
1385 }
1386
1387 void ContentSecurityPolicy::reportInvalidPathCharacter(
1388 const String& directiveName,
1389 const String& value,
1390 const char invalidChar) {
1391 ASSERT(invalidChar == '#' || invalidChar == '?');
1392
1393 String ignoring =
1394 "The fragment identifier, including the '#', will be ignored.";
1395 if (invalidChar == '?')
1396 ignoring = "The query component, including the '?', will be ignored.";
1397 String message = "The source list for Content Security Policy directive '" +
1398 directiveName +
1399 "' contains a source with an invalid path: '" + value +
1400 "'. " + ignoring;
1401 logToConsole(message);
1402 }
1403
1404 void ContentSecurityPolicy::reportInvalidSourceExpression(
1405 const String& directiveName,
1406 const String& source) {
1407 String message = "The source list for Content Security Policy directive '" +
1408 directiveName + "' contains an invalid source: '" + source +
1409 "'. It will be ignored.";
1410 if (equalIgnoringCase(source, "'none'"))
1411 message = message +
1412 " Note that 'none' has no effect unless it is the only "
1413 "expression in the source list.";
1414 logToConsole(message);
1415 }
1416
1417 void ContentSecurityPolicy::reportMissingReportURI(const String& policy) {
1418 logToConsole("The Content Security Policy '" + policy +
1419 "' was delivered in report-only mode, but does not specify a "
1420 "'report-uri'; the policy will have no effect. Please either "
1421 "add a 'report-uri' directive, or deliver the policy via the "
1422 "'Content-Security-Policy' header.");
1423 }
1424
1425 void ContentSecurityPolicy::logToConsole(const String& message,
1426 MessageLevel level) {
1427 logToConsole(ConsoleMessage::create(SecurityMessageSource, level, message));
1428 }
1429
1430 void ContentSecurityPolicy::logToConsole(ConsoleMessage* consoleMessage,
1431 LocalFrame* frame) {
1432 if (frame)
1433 frame->document()->addConsoleMessage(consoleMessage);
1434 else if (m_executionContext)
1435 m_executionContext->addConsoleMessage(consoleMessage);
1436 else
1437 m_consoleMessages.append(consoleMessage);
1438 }
1439
1440 void ContentSecurityPolicy::reportBlockedScriptExecutionToInspector(
1441 const String& directiveText) const {
1442 InspectorInstrumentation::scriptExecutionBlockedByCSP(m_executionContext,
1443 directiveText);
1444 }
1445
1446 bool ContentSecurityPolicy::experimentalFeaturesEnabled() const {
1447 return RuntimeEnabledFeatures::
1448 experimentalContentSecurityPolicyFeaturesEnabled();
1449 }
1450
1451 bool ContentSecurityPolicy::shouldSendCSPHeader(Resource::Type type) const {
1452 for (const auto& policy : m_policies) {
1453 if (policy->shouldSendCSPHeader(type))
1454 return true;
1455 }
1456 return false;
1457 }
1458
1459 bool ContentSecurityPolicy::urlMatchesSelf(const KURL& url) const {
1460 return m_selfSource->matches(url, RedirectStatus::NoRedirect);
1461 }
1462
1463 bool ContentSecurityPolicy::protocolMatchesSelf(const KURL& url) const {
1464 if (equalIgnoringCase("http", m_selfProtocol))
1465 return url.protocolIsInHTTPFamily();
1466 return equalIgnoringCase(url.protocol(), m_selfProtocol);
1467 }
1468
1469 bool ContentSecurityPolicy::selfMatchesInnerURL() const {
1470 // Due to backwards-compatibility concerns, we allow 'self' to match blob and
1471 // filesystem URLs if we're in a context that bypasses Content Security Policy
1472 // in the main world.
1473 //
1474 // TODO(mkwst): Revisit this once embedders have an opportunity to update
1475 // their extension models.
1476 return m_executionContext &&
1477 SchemeRegistry::schemeShouldBypassContentSecurityPolicy(
1478 m_executionContext->getSecurityOrigin()->protocol());
1479 }
1480
1481 bool ContentSecurityPolicy::shouldBypassMainWorld(
1482 const ExecutionContext* context) {
1483 if (context && context->isDocument()) {
1484 const Document* document = toDocument(context);
1485 if (document->frame())
1486 return document->frame()->script().shouldBypassMainWorldCSP();
1487 }
1488 return false;
1489 }
1490
1491 bool ContentSecurityPolicy::shouldSendViolationReport(
1492 const String& report) const {
1493 // Collisions have no security impact, so we can save space by storing only
1494 // the string's hash rather than the whole report.
1495 return !m_violationReportsSent.contains(report.impl()->hash());
1496 }
1497
1498 void ContentSecurityPolicy::didSendViolationReport(const String& report) {
1499 m_violationReportsSent.add(report.impl()->hash());
1500 }
1501 1573
1502 } // namespace blink 1574 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698