| OLD | NEW |
| 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 24 matching lines...) Expand all Loading... |
| 35 #include "core/events/SecurityPolicyViolationEvent.h" | 35 #include "core/events/SecurityPolicyViolationEvent.h" |
| 36 #include "core/frame/ContentSecurityPolicyResponseHeaders.h" | 36 #include "core/frame/ContentSecurityPolicyResponseHeaders.h" |
| 37 #include "core/frame/DOMWindow.h" | 37 #include "core/frame/DOMWindow.h" |
| 38 #include "core/frame/Frame.h" | 38 #include "core/frame/Frame.h" |
| 39 #include "core/inspector/InspectorInstrumentation.h" | 39 #include "core/inspector/InspectorInstrumentation.h" |
| 40 #include "core/inspector/ScriptCallStack.h" | 40 #include "core/inspector/ScriptCallStack.h" |
| 41 #include "core/loader/DocumentLoader.h" | 41 #include "core/loader/DocumentLoader.h" |
| 42 #include "core/loader/PingLoader.h" | 42 #include "core/loader/PingLoader.h" |
| 43 #include "core/page/UseCounter.h" | 43 #include "core/page/UseCounter.h" |
| 44 #include "platform/JSONValues.h" | 44 #include "platform/JSONValues.h" |
| 45 #include "platform/NotImplemented.h" |
| 45 #include "platform/ParsingUtilities.h" | 46 #include "platform/ParsingUtilities.h" |
| 46 #include "platform/network/FormData.h" | 47 #include "platform/network/FormData.h" |
| 47 #include "platform/network/ResourceResponse.h" | 48 #include "platform/network/ResourceResponse.h" |
| 48 #include "weborigin/KURL.h" | 49 #include "weborigin/KURL.h" |
| 49 #include "weborigin/KnownPorts.h" | 50 #include "weborigin/KnownPorts.h" |
| 50 #include "weborigin/SchemeRegistry.h" | 51 #include "weborigin/SchemeRegistry.h" |
| 51 #include "weborigin/SecurityOrigin.h" | 52 #include "weborigin/SecurityOrigin.h" |
| 52 #include "wtf/HashSet.h" | 53 #include "wtf/HashSet.h" |
| 54 #include "wtf/SHA1.h" |
| 55 #include "wtf/StringHasher.h" |
| 56 #include "wtf/text/Base64.h" |
| 57 #include "wtf/text/StringBuilder.h" |
| 53 #include "wtf/text/TextPosition.h" | 58 #include "wtf/text/TextPosition.h" |
| 54 #include "wtf/text/WTFString.h" | 59 #include "wtf/text/WTFString.h" |
| 55 | 60 |
| 61 namespace WTF { |
| 62 |
| 63 struct VectorIntHash { |
| 64 static unsigned hash(const Vector<uint8_t>& v) { return StringHasher::comput
eHash(v.data(), v.size()); } |
| 65 static bool equal(const Vector<uint8_t>& a, const Vector<uint8_t>& b) { retu
rn a == b; }; |
| 66 static const bool safeToCompareToEmptyOrDeleted = true; |
| 67 }; |
| 68 template<> struct DefaultHash<Vector<uint8_t> > { |
| 69 typedef VectorIntHash Hash; |
| 70 }; |
| 71 |
| 72 } // namespace WTF |
| 73 |
| 56 namespace WebCore { | 74 namespace WebCore { |
| 57 | 75 |
| 76 typedef std::pair<unsigned, Vector<uint8_t> > SourceHashValue; |
| 77 |
| 58 // Normally WebKit uses "static" for internal linkage, but using "static" for | 78 // Normally WebKit uses "static" for internal linkage, but using "static" for |
| 59 // these functions causes a compile error because these functions are used as | 79 // these functions causes a compile error because these functions are used as |
| 60 // template parameters. | 80 // template parameters. |
| 61 namespace { | 81 namespace { |
| 62 | 82 |
| 63 bool isDirectiveNameCharacter(UChar c) | 83 bool isDirectiveNameCharacter(UChar c) |
| 64 { | 84 { |
| 65 return isASCIIAlphanumeric(c) || c == '-'; | 85 return isASCIIAlphanumeric(c) || c == '-'; |
| 66 } | 86 } |
| 67 | 87 |
| 68 bool isDirectiveValueCharacter(UChar c) | 88 bool isDirectiveValueCharacter(UChar c) |
| 69 { | 89 { |
| 70 return isASCIISpace(c) || (c >= 0x21 && c <= 0x7e); // Whitespace + VCHAR | 90 return isASCIISpace(c) || (c >= 0x21 && c <= 0x7e); // Whitespace + VCHAR |
| 71 } | 91 } |
| 72 | 92 |
| 73 bool isNonceCharacter(UChar c) | 93 // Only checks for general Base64 encoded chars, not '=' chars since '=' is |
| 94 // positional and may only appear at the end of a Base64 encoded string. |
| 95 bool isBase64EncodedCharacter(UChar c) |
| 74 { | 96 { |
| 75 return isASCIIAlphanumeric(c) || c == '+' || c == '/'; | 97 return isASCIIAlphanumeric(c) || c == '+' || c == '/'; |
| 76 } | 98 } |
| 77 | 99 |
| 78 bool isSourceCharacter(UChar c) | 100 bool isSourceCharacter(UChar c) |
| 79 { | 101 { |
| 80 return !isASCIISpace(c); | 102 return !isASCIISpace(c); |
| 81 } | 103 } |
| 82 | 104 |
| 83 bool isPathComponentCharacter(UChar c) | 105 bool isPathComponentCharacter(UChar c) |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 class CSPSourceList { | 291 class CSPSourceList { |
| 270 public: | 292 public: |
| 271 CSPSourceList(ContentSecurityPolicy*, const String& directiveName); | 293 CSPSourceList(ContentSecurityPolicy*, const String& directiveName); |
| 272 | 294 |
| 273 void parse(const UChar* begin, const UChar* end); | 295 void parse(const UChar* begin, const UChar* end); |
| 274 | 296 |
| 275 bool matches(const KURL&); | 297 bool matches(const KURL&); |
| 276 bool allowInline() const { return m_allowInline; } | 298 bool allowInline() const { return m_allowInline; } |
| 277 bool allowEval() const { return m_allowEval; } | 299 bool allowEval() const { return m_allowEval; } |
| 278 bool allowNonce(const String& nonce) const { return !nonce.isNull() && m_non
ces.contains(nonce); } | 300 bool allowNonce(const String& nonce) const { return !nonce.isNull() && m_non
ces.contains(nonce); } |
| 301 bool allowHash(const SourceHashValue& hashValue) const { return m_hashes.con
tains(hashValue); } |
| 302 uint8_t hashAlgorithmsUsed() const { return m_hashAlgorithmsUsed; } |
| 279 | 303 |
| 280 private: | 304 private: |
| 281 bool parseSource(const UChar* begin, const UChar* end, String& scheme, Strin
g& host, int& port, String& path, bool& hostHasWildcard, bool& portHasWildcard); | 305 bool parseSource(const UChar* begin, const UChar* end, String& scheme, Strin
g& host, int& port, String& path, bool& hostHasWildcard, bool& portHasWildcard); |
| 282 bool parseScheme(const UChar* begin, const UChar* end, String& scheme); | 306 bool parseScheme(const UChar* begin, const UChar* end, String& scheme); |
| 283 bool parseHost(const UChar* begin, const UChar* end, String& host, bool& hos
tHasWildcard); | 307 bool parseHost(const UChar* begin, const UChar* end, String& host, bool& hos
tHasWildcard); |
| 284 bool parsePort(const UChar* begin, const UChar* end, int& port, bool& portHa
sWildcard); | 308 bool parsePort(const UChar* begin, const UChar* end, int& port, bool& portHa
sWildcard); |
| 285 bool parsePath(const UChar* begin, const UChar* end, String& path); | 309 bool parsePath(const UChar* begin, const UChar* end, String& path); |
| 286 bool parseNonce(const UChar* begin, const UChar* end, String& nonce); | 310 bool parseNonce(const UChar* begin, const UChar* end, String& nonce); |
| 311 bool parseHash(const UChar* begin, const UChar* end, Vector<uint8_t>& hash,
ContentSecurityPolicy::HashAlgorithms&); |
| 287 | 312 |
| 288 void addSourceSelf(); | 313 void addSourceSelf(); |
| 289 void addSourceStar(); | 314 void addSourceStar(); |
| 290 void addSourceUnsafeInline(); | 315 void addSourceUnsafeInline(); |
| 291 void addSourceUnsafeEval(); | 316 void addSourceUnsafeEval(); |
| 292 void addSourceNonce(const String& nonce); | 317 void addSourceNonce(const String& nonce); |
| 318 void addSourceHash(const ContentSecurityPolicy::HashAlgorithms&, const Vecto
r<uint8_t>& hash); |
| 293 | 319 |
| 294 ContentSecurityPolicy* m_policy; | 320 ContentSecurityPolicy* m_policy; |
| 295 Vector<CSPSource> m_list; | 321 Vector<CSPSource> m_list; |
| 296 String m_directiveName; | 322 String m_directiveName; |
| 297 bool m_allowStar; | 323 bool m_allowStar; |
| 298 bool m_allowInline; | 324 bool m_allowInline; |
| 299 bool m_allowEval; | 325 bool m_allowEval; |
| 300 HashSet<String> m_nonces; | 326 HashSet<String> m_nonces; |
| 327 HashSet<SourceHashValue> m_hashes; |
| 328 uint8_t m_hashAlgorithmsUsed; |
| 301 }; | 329 }; |
| 302 | 330 |
| 303 CSPSourceList::CSPSourceList(ContentSecurityPolicy* policy, const String& direct
iveName) | 331 CSPSourceList::CSPSourceList(ContentSecurityPolicy* policy, const String& direct
iveName) |
| 304 : m_policy(policy) | 332 : m_policy(policy) |
| 305 , m_directiveName(directiveName) | 333 , m_directiveName(directiveName) |
| 306 , m_allowStar(false) | 334 , m_allowStar(false) |
| 307 , m_allowInline(false) | 335 , m_allowInline(false) |
| 308 , m_allowEval(false) | 336 , m_allowEval(false) |
| 337 , m_hashAlgorithmsUsed(0) |
| 309 { | 338 { |
| 310 } | 339 } |
| 311 | 340 |
| 312 bool CSPSourceList::matches(const KURL& url) | 341 bool CSPSourceList::matches(const KURL& url) |
| 313 { | 342 { |
| 314 if (m_allowStar) | 343 if (m_allowStar) |
| 315 return true; | 344 return true; |
| 316 | 345 |
| 317 KURL effectiveURL = SecurityOrigin::shouldUseInnerURL(url) ? SecurityOrigin:
:extractInnerURL(url) : url; | 346 KURL effectiveURL = SecurityOrigin::shouldUseInnerURL(url) ? SecurityOrigin:
:extractInnerURL(url) : url; |
| 318 | 347 |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 | 426 |
| 398 if (m_policy->experimentalFeaturesEnabled()) { | 427 if (m_policy->experimentalFeaturesEnabled()) { |
| 399 String nonce; | 428 String nonce; |
| 400 if (!parseNonce(begin, end, nonce)) | 429 if (!parseNonce(begin, end, nonce)) |
| 401 return false; | 430 return false; |
| 402 | 431 |
| 403 if (!nonce.isNull()) { | 432 if (!nonce.isNull()) { |
| 404 addSourceNonce(nonce); | 433 addSourceNonce(nonce); |
| 405 return true; | 434 return true; |
| 406 } | 435 } |
| 436 |
| 437 Vector<uint8_t> hash; |
| 438 ContentSecurityPolicy::HashAlgorithms algorithm = ContentSecurityPolicy:
:HashAlgorithmsNone; |
| 439 if (!parseHash(begin, end, hash, algorithm)) |
| 440 return false; |
| 441 |
| 442 if (hash.size() > 0) { |
| 443 addSourceHash(algorithm, hash); |
| 444 return true; |
| 445 } |
| 407 } | 446 } |
| 408 | 447 |
| 409 const UChar* position = begin; | 448 const UChar* position = begin; |
| 410 const UChar* beginHost = begin; | 449 const UChar* beginHost = begin; |
| 411 const UChar* beginPath = end; | 450 const UChar* beginPath = end; |
| 412 const UChar* beginPort = 0; | 451 const UChar* beginPort = 0; |
| 413 | 452 |
| 414 skipWhile<UChar, isNotColonOrSlash>(position, end); | 453 skipWhile<UChar, isNotColonOrSlash>(position, end); |
| 415 | 454 |
| 416 if (position == end) { | 455 if (position == end) { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 486 bool CSPSourceList::parseNonce(const UChar* begin, const UChar* end, String& non
ce) | 525 bool CSPSourceList::parseNonce(const UChar* begin, const UChar* end, String& non
ce) |
| 487 { | 526 { |
| 488 DEFINE_STATIC_LOCAL(const String, noncePrefix, ("'nonce-")); | 527 DEFINE_STATIC_LOCAL(const String, noncePrefix, ("'nonce-")); |
| 489 | 528 |
| 490 if (!equalIgnoringCase(noncePrefix.characters8(), begin, noncePrefix.length(
))) | 529 if (!equalIgnoringCase(noncePrefix.characters8(), begin, noncePrefix.length(
))) |
| 491 return true; | 530 return true; |
| 492 | 531 |
| 493 const UChar* position = begin + noncePrefix.length(); | 532 const UChar* position = begin + noncePrefix.length(); |
| 494 const UChar* nonceBegin = position; | 533 const UChar* nonceBegin = position; |
| 495 | 534 |
| 496 skipWhile<UChar, isNonceCharacter>(position, end); | 535 skipWhile<UChar, isBase64EncodedCharacter>(position, end); |
| 497 ASSERT(nonceBegin <= position); | 536 ASSERT(nonceBegin <= position); |
| 498 | 537 |
| 499 if (((position + 1) != end && *position != '\'') || !(position - nonceBegin
)) | 538 if ((position + 1) != end || *position != '\'' || !(position - nonceBegin)) |
| 500 return false; | 539 return false; |
| 501 | 540 |
| 502 nonce = String(nonceBegin, position - nonceBegin); | 541 nonce = String(nonceBegin, position - nonceBegin); |
| 503 return true; | 542 return true; |
| 504 } | 543 } |
| 505 | 544 |
| 545 // hash-source = "'" hash-algorithm "-" hash-value "'" |
| 546 // hash-algorithm = "sha1" / "sha256" |
| 547 // hash-value = 1*( ALPHA / DIGIT / "+" / "/" / "=" ) |
| 548 // |
| 549 bool CSPSourceList::parseHash(const UChar* begin, const UChar* end, Vector<uint8
_t>& hash, ContentSecurityPolicy::HashAlgorithms& hashAlgorithm) |
| 550 { |
| 551 DEFINE_STATIC_LOCAL(const String, sha1Prefix, ("'sha1-")); |
| 552 DEFINE_STATIC_LOCAL(const String, sha256Prefix, ("'sha256-")); |
| 553 |
| 554 String prefix; |
| 555 if (equalIgnoringCase(sha1Prefix.characters8(), begin, sha1Prefix.length()))
{ |
| 556 prefix = sha1Prefix; |
| 557 hashAlgorithm = ContentSecurityPolicy::HashAlgorithmsSha1; |
| 558 } else if (equalIgnoringCase(sha256Prefix.characters8(), begin, sha256Prefix
.length())) { |
| 559 notImplemented(); |
| 560 } else { |
| 561 return true; |
| 562 } |
| 563 |
| 564 const UChar* position = begin + prefix.length(); |
| 565 const UChar* hashBegin = position; |
| 566 |
| 567 skipWhile<UChar, isBase64EncodedCharacter>(position, end); |
| 568 ASSERT(hashBegin <= position); |
| 569 |
| 570 // Base64 encodings may end with exactly one or two '=' characters |
| 571 skipExactly<UChar>(position, position + 1, '='); |
| 572 skipExactly<UChar>(position, position + 1, '='); |
| 573 |
| 574 if ((position + 1) != end || *position != '\'' || !(position - hashBegin)) |
| 575 return false; |
| 576 |
| 577 Vector<char> hashVector; |
| 578 base64Decode(hashBegin, position - hashBegin, hashVector); |
| 579 hash.append(reinterpret_cast<uint8_t*>(hashVector.data()), hashVector.size()
); |
| 580 return true; |
| 581 } |
| 582 |
| 506 // ; <scheme> production from RFC 3986 | 583 // ; <scheme> production from RFC 3986 |
| 507 // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) | 584 // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) |
| 508 // | 585 // |
| 509 bool CSPSourceList::parseScheme(const UChar* begin, const UChar* end, String& sc
heme) | 586 bool CSPSourceList::parseScheme(const UChar* begin, const UChar* end, String& sc
heme) |
| 510 { | 587 { |
| 511 ASSERT(begin <= end); | 588 ASSERT(begin <= end); |
| 512 ASSERT(scheme.isEmpty()); | 589 ASSERT(scheme.isEmpty()); |
| 513 | 590 |
| 514 if (begin == end) | 591 if (begin == end) |
| 515 return false; | 592 return false; |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 638 void CSPSourceList::addSourceUnsafeEval() | 715 void CSPSourceList::addSourceUnsafeEval() |
| 639 { | 716 { |
| 640 m_allowEval = true; | 717 m_allowEval = true; |
| 641 } | 718 } |
| 642 | 719 |
| 643 void CSPSourceList::addSourceNonce(const String& nonce) | 720 void CSPSourceList::addSourceNonce(const String& nonce) |
| 644 { | 721 { |
| 645 m_nonces.add(nonce); | 722 m_nonces.add(nonce); |
| 646 } | 723 } |
| 647 | 724 |
| 725 void CSPSourceList::addSourceHash(const ContentSecurityPolicy::HashAlgorithms& a
lgorithm, const Vector<uint8_t>& hash) |
| 726 { |
| 727 m_hashes.add(SourceHashValue(algorithm, hash)); |
| 728 m_hashAlgorithmsUsed |= algorithm; |
| 729 } |
| 730 |
| 648 class CSPDirective { | 731 class CSPDirective { |
| 649 public: | 732 public: |
| 650 CSPDirective(const String& name, const String& value, ContentSecurityPolicy*
policy) | 733 CSPDirective(const String& name, const String& value, ContentSecurityPolicy*
policy) |
| 651 : m_name(name) | 734 : m_name(name) |
| 652 , m_text(name + ' ' + value) | 735 , m_text(name + ' ' + value) |
| 653 , m_policy(policy) | 736 , m_policy(policy) |
| 654 { | 737 { |
| 655 } | 738 } |
| 656 | 739 |
| 657 const String& text() const { return m_text; } | 740 const String& text() const { return m_text; } |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 754 } | 837 } |
| 755 | 838 |
| 756 bool allows(const KURL& url) | 839 bool allows(const KURL& url) |
| 757 { | 840 { |
| 758 return m_sourceList.matches(url.isEmpty() ? policy()->url() : url); | 841 return m_sourceList.matches(url.isEmpty() ? policy()->url() : url); |
| 759 } | 842 } |
| 760 | 843 |
| 761 bool allowInline() const { return m_sourceList.allowInline(); } | 844 bool allowInline() const { return m_sourceList.allowInline(); } |
| 762 bool allowEval() const { return m_sourceList.allowEval(); } | 845 bool allowEval() const { return m_sourceList.allowEval(); } |
| 763 bool allowNonce(const String& nonce) const { return m_sourceList.allowNonce(
nonce.stripWhiteSpace()); } | 846 bool allowNonce(const String& nonce) const { return m_sourceList.allowNonce(
nonce.stripWhiteSpace()); } |
| 847 bool allowHash(const SourceHashValue& hashValue) const { return m_sourceList
.allowHash(hashValue); } |
| 848 |
| 849 uint8_t hashAlgorithmsUsed() const { return m_sourceList.hashAlgorithmsUsed(
); } |
| 764 | 850 |
| 765 private: | 851 private: |
| 766 CSPSourceList m_sourceList; | 852 CSPSourceList m_sourceList; |
| 767 }; | 853 }; |
| 768 | 854 |
| 769 class CSPDirectiveList { | 855 class CSPDirectiveList { |
| 770 WTF_MAKE_FAST_ALLOCATED; | 856 WTF_MAKE_FAST_ALLOCATED; |
| 771 public: | 857 public: |
| 772 static PassOwnPtr<CSPDirectiveList> create(ContentSecurityPolicy*, const UCh
ar* begin, const UChar* end, ContentSecurityPolicy::HeaderType); | 858 static PassOwnPtr<CSPDirectiveList> create(ContentSecurityPolicy*, const UCh
ar* begin, const UChar* end, ContentSecurityPolicy::HeaderType); |
| 773 | 859 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 788 bool allowChildFrameFromSource(const KURL&, ContentSecurityPolicy::Reporting
Status) const; | 874 bool allowChildFrameFromSource(const KURL&, ContentSecurityPolicy::Reporting
Status) const; |
| 789 bool allowImageFromSource(const KURL&, ContentSecurityPolicy::ReportingStatu
s) const; | 875 bool allowImageFromSource(const KURL&, ContentSecurityPolicy::ReportingStatu
s) const; |
| 790 bool allowStyleFromSource(const KURL&, ContentSecurityPolicy::ReportingStatu
s) const; | 876 bool allowStyleFromSource(const KURL&, ContentSecurityPolicy::ReportingStatu
s) const; |
| 791 bool allowFontFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus
) const; | 877 bool allowFontFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus
) const; |
| 792 bool allowMediaFromSource(const KURL&, ContentSecurityPolicy::ReportingStatu
s) const; | 878 bool allowMediaFromSource(const KURL&, ContentSecurityPolicy::ReportingStatu
s) const; |
| 793 bool allowConnectToSource(const KURL&, ContentSecurityPolicy::ReportingStatu
s) const; | 879 bool allowConnectToSource(const KURL&, ContentSecurityPolicy::ReportingStatu
s) const; |
| 794 bool allowFormAction(const KURL&, ContentSecurityPolicy::ReportingStatus) co
nst; | 880 bool allowFormAction(const KURL&, ContentSecurityPolicy::ReportingStatus) co
nst; |
| 795 bool allowBaseURI(const KURL&, ContentSecurityPolicy::ReportingStatus) const
; | 881 bool allowBaseURI(const KURL&, ContentSecurityPolicy::ReportingStatus) const
; |
| 796 bool allowScriptNonce(const String&) const; | 882 bool allowScriptNonce(const String&) const; |
| 797 bool allowStyleNonce(const String&) const; | 883 bool allowStyleNonce(const String&) const; |
| 884 bool allowScriptHash(const SourceHashValue&) const; |
| 798 | 885 |
| 799 void gatherReportURIs(DOMStringList&) const; | 886 void gatherReportURIs(DOMStringList&) const; |
| 800 const String& evalDisabledErrorMessage() const { return m_evalDisabledErrorM
essage; } | 887 const String& evalDisabledErrorMessage() const { return m_evalDisabledErrorM
essage; } |
| 801 ReflectedXSSDisposition reflectedXSSDisposition() const { return m_reflected
XSSDisposition; } | 888 ReflectedXSSDisposition reflectedXSSDisposition() const { return m_reflected
XSSDisposition; } |
| 802 bool isReportOnly() const { return m_reportOnly; } | 889 bool isReportOnly() const { return m_reportOnly; } |
| 803 const Vector<KURL>& reportURIs() const { return m_reportURIs; } | 890 const Vector<KURL>& reportURIs() const { return m_reportURIs; } |
| 804 | 891 |
| 805 private: | 892 private: |
| 806 CSPDirectiveList(ContentSecurityPolicy*, ContentSecurityPolicy::HeaderType); | 893 CSPDirectiveList(ContentSecurityPolicy*, ContentSecurityPolicy::HeaderType); |
| 807 | 894 |
| 808 bool parseDirective(const UChar* begin, const UChar* end, String& name, Stri
ng& value); | 895 bool parseDirective(const UChar* begin, const UChar* end, String& name, Stri
ng& value); |
| 809 void parseReportURI(const String& name, const String& value); | 896 void parseReportURI(const String& name, const String& value); |
| 810 void parsePluginTypes(const String& name, const String& value); | 897 void parsePluginTypes(const String& name, const String& value); |
| 811 void parseReflectedXSS(const String& name, const String& value); | 898 void parseReflectedXSS(const String& name, const String& value); |
| 812 void addDirective(const String& name, const String& value); | 899 void addDirective(const String& name, const String& value); |
| 813 void applySandboxPolicy(const String& name, const String& sandboxPolicy); | 900 void applySandboxPolicy(const String& name, const String& sandboxPolicy); |
| 814 | 901 |
| 815 template <class CSPDirectiveType> | 902 template <class CSPDirectiveType> |
| 816 void setCSPDirective(const String& name, const String& value, OwnPtr<CSPDire
ctiveType>&); | 903 void setCSPDirective(const String& name, const String& value, OwnPtr<CSPDire
ctiveType>&); |
| 817 | 904 |
| 818 SourceListDirective* operativeDirective(SourceListDirective*) const; | 905 SourceListDirective* operativeDirective(SourceListDirective*) const; |
| 819 void reportViolation(const String& directiveText, const String& effectiveDir
ective, const String& consoleMessage, const KURL& blockedURL) const; | 906 void reportViolation(const String& directiveText, const String& effectiveDir
ective, const String& consoleMessage, const KURL& blockedURL) const; |
| 820 void reportViolationWithLocation(const String& directiveText, const String&
effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const
String& contextURL, const WTF::OrdinalNumber& contextLine) const; | 907 void reportViolationWithLocation(const String& directiveText, const String&
effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const
String& contextURL, const WTF::OrdinalNumber& contextLine) const; |
| 821 void reportViolationWithState(const String& directiveText, const String& eff
ectiveDirective, const String& consoleMessage, const KURL& blockedURL, ScriptSta
te*) const; | 908 void reportViolationWithState(const String& directiveText, const String& eff
ectiveDirective, const String& consoleMessage, const KURL& blockedURL, ScriptSta
te*) const; |
| 822 | 909 |
| 823 bool checkEval(SourceListDirective*) const; | 910 bool checkEval(SourceListDirective*) const; |
| 824 bool checkInline(SourceListDirective*) const; | 911 bool checkInline(SourceListDirective*) const; |
| 825 bool checkNonce(SourceListDirective*, const String&) const; | 912 bool checkNonce(SourceListDirective*, const String&) const; |
| 913 bool checkHash(SourceListDirective*, const SourceHashValue&) const; |
| 826 bool checkSource(SourceListDirective*, const KURL&) const; | 914 bool checkSource(SourceListDirective*, const KURL&) const; |
| 827 bool checkMediaType(MediaListDirective*, const String& type, const String& t
ypeAttribute) const; | 915 bool checkMediaType(MediaListDirective*, const String& type, const String& t
ypeAttribute) const; |
| 828 | 916 |
| 829 void setEvalDisabledErrorMessage(const String& errorMessage) { m_evalDisable
dErrorMessage = errorMessage; } | 917 void setEvalDisabledErrorMessage(const String& errorMessage) { m_evalDisable
dErrorMessage = errorMessage; } |
| 830 | 918 |
| 831 bool checkEvalAndReportViolation(SourceListDirective*, const String& console
Message, ScriptState*) const; | 919 bool checkEvalAndReportViolation(SourceListDirective*, const String& console
Message, ScriptState*) const; |
| 832 bool checkInlineAndReportViolation(SourceListDirective*, const String& conso
leMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine, bool
isScript) const; | 920 bool checkInlineAndReportViolation(SourceListDirective*, const String& conso
leMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine, bool
isScript) const; |
| 833 | 921 |
| 834 bool checkSourceAndReportViolation(SourceListDirective*, const KURL&, const
String& effectiveDirective) const; | 922 bool checkSourceAndReportViolation(SourceListDirective*, const KURL&, const
String& effectiveDirective) const; |
| 835 bool checkMediaTypeAndReportViolation(MediaListDirective*, const String& typ
e, const String& typeAttribute, const String& consoleMessage) const; | 923 bool checkMediaTypeAndReportViolation(MediaListDirective*, const String& typ
e, const String& typeAttribute, const String& consoleMessage) const; |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 918 bool CSPDirectiveList::checkInline(SourceListDirective* directive) const | 1006 bool CSPDirectiveList::checkInline(SourceListDirective* directive) const |
| 919 { | 1007 { |
| 920 return !directive || directive->allowInline(); | 1008 return !directive || directive->allowInline(); |
| 921 } | 1009 } |
| 922 | 1010 |
| 923 bool CSPDirectiveList::checkNonce(SourceListDirective* directive, const String&
nonce) const | 1011 bool CSPDirectiveList::checkNonce(SourceListDirective* directive, const String&
nonce) const |
| 924 { | 1012 { |
| 925 return !directive || directive->allowNonce(nonce); | 1013 return !directive || directive->allowNonce(nonce); |
| 926 } | 1014 } |
| 927 | 1015 |
| 1016 bool CSPDirectiveList::checkHash(SourceListDirective* directive, const SourceHas
hValue& hashValue) const |
| 1017 { |
| 1018 return !directive || directive->allowHash(hashValue); |
| 1019 } |
| 1020 |
| 928 bool CSPDirectiveList::checkSource(SourceListDirective* directive, const KURL& u
rl) const | 1021 bool CSPDirectiveList::checkSource(SourceListDirective* directive, const KURL& u
rl) const |
| 929 { | 1022 { |
| 930 return !directive || directive->allows(url); | 1023 return !directive || directive->allows(url); |
| 931 } | 1024 } |
| 932 | 1025 |
| 933 bool CSPDirectiveList::checkMediaType(MediaListDirective* directive, const Strin
g& type, const String& typeAttribute) const | 1026 bool CSPDirectiveList::checkMediaType(MediaListDirective* directive, const Strin
g& type, const String& typeAttribute) const |
| 934 { | 1027 { |
| 935 if (!directive) | 1028 if (!directive) |
| 936 return true; | 1029 return true; |
| 937 if (typeAttribute.isEmpty() || typeAttribute.stripWhiteSpace() != type) | 1030 if (typeAttribute.isEmpty() || typeAttribute.stripWhiteSpace() != type) |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1160 bool CSPDirectiveList::allowScriptNonce(const String& nonce) const | 1253 bool CSPDirectiveList::allowScriptNonce(const String& nonce) const |
| 1161 { | 1254 { |
| 1162 return checkNonce(operativeDirective(m_scriptSrc.get()), nonce); | 1255 return checkNonce(operativeDirective(m_scriptSrc.get()), nonce); |
| 1163 } | 1256 } |
| 1164 | 1257 |
| 1165 bool CSPDirectiveList::allowStyleNonce(const String& nonce) const | 1258 bool CSPDirectiveList::allowStyleNonce(const String& nonce) const |
| 1166 { | 1259 { |
| 1167 return checkNonce(operativeDirective(m_styleSrc.get()), nonce); | 1260 return checkNonce(operativeDirective(m_styleSrc.get()), nonce); |
| 1168 } | 1261 } |
| 1169 | 1262 |
| 1263 bool CSPDirectiveList::allowScriptHash(const SourceHashValue& hashValue) const |
| 1264 { |
| 1265 return checkHash(operativeDirective(m_scriptSrc.get()), hashValue); |
| 1266 } |
| 1267 |
| 1170 // policy = directive-list | 1268 // policy = directive-list |
| 1171 // directive-list = [ directive *( ";" [ directive ] ) ] | 1269 // directive-list = [ directive *( ";" [ directive ] ) ] |
| 1172 // | 1270 // |
| 1173 void CSPDirectiveList::parse(const UChar* begin, const UChar* end) | 1271 void CSPDirectiveList::parse(const UChar* begin, const UChar* end) |
| 1174 { | 1272 { |
| 1175 m_header = String(begin, end - begin); | 1273 m_header = String(begin, end - begin); |
| 1176 | 1274 |
| 1177 if (begin == end) | 1275 if (begin == end) |
| 1178 return; | 1276 return; |
| 1179 | 1277 |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1347 } | 1445 } |
| 1348 | 1446 |
| 1349 void CSPDirectiveList::addDirective(const String& name, const String& value) | 1447 void CSPDirectiveList::addDirective(const String& name, const String& value) |
| 1350 { | 1448 { |
| 1351 ASSERT(!name.isEmpty()); | 1449 ASSERT(!name.isEmpty()); |
| 1352 | 1450 |
| 1353 if (equalIgnoringCase(name, defaultSrc)) { | 1451 if (equalIgnoringCase(name, defaultSrc)) { |
| 1354 setCSPDirective<SourceListDirective>(name, value, m_defaultSrc); | 1452 setCSPDirective<SourceListDirective>(name, value, m_defaultSrc); |
| 1355 } else if (equalIgnoringCase(name, scriptSrc)) { | 1453 } else if (equalIgnoringCase(name, scriptSrc)) { |
| 1356 setCSPDirective<SourceListDirective>(name, value, m_scriptSrc); | 1454 setCSPDirective<SourceListDirective>(name, value, m_scriptSrc); |
| 1455 m_policy->usesScriptHashAlgorithms(m_scriptSrc->hashAlgorithmsUsed()); |
| 1357 } else if (equalIgnoringCase(name, objectSrc)) { | 1456 } else if (equalIgnoringCase(name, objectSrc)) { |
| 1358 setCSPDirective<SourceListDirective>(name, value, m_objectSrc); | 1457 setCSPDirective<SourceListDirective>(name, value, m_objectSrc); |
| 1359 } else if (equalIgnoringCase(name, frameSrc)) { | 1458 } else if (equalIgnoringCase(name, frameSrc)) { |
| 1360 setCSPDirective<SourceListDirective>(name, value, m_frameSrc); | 1459 setCSPDirective<SourceListDirective>(name, value, m_frameSrc); |
| 1361 } else if (equalIgnoringCase(name, imgSrc)) { | 1460 } else if (equalIgnoringCase(name, imgSrc)) { |
| 1362 setCSPDirective<SourceListDirective>(name, value, m_imgSrc); | 1461 setCSPDirective<SourceListDirective>(name, value, m_imgSrc); |
| 1363 } else if (equalIgnoringCase(name, styleSrc)) { | 1462 } else if (equalIgnoringCase(name, styleSrc)) { |
| 1364 setCSPDirective<SourceListDirective>(name, value, m_styleSrc); | 1463 setCSPDirective<SourceListDirective>(name, value, m_styleSrc); |
| 1365 } else if (equalIgnoringCase(name, fontSrc)) { | 1464 } else if (equalIgnoringCase(name, fontSrc)) { |
| 1366 setCSPDirective<SourceListDirective>(name, value, m_fontSrc); | 1465 setCSPDirective<SourceListDirective>(name, value, m_fontSrc); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1384 else | 1483 else |
| 1385 m_policy->reportUnsupportedDirective(name); | 1484 m_policy->reportUnsupportedDirective(name); |
| 1386 } else { | 1485 } else { |
| 1387 m_policy->reportUnsupportedDirective(name); | 1486 m_policy->reportUnsupportedDirective(name); |
| 1388 } | 1487 } |
| 1389 } | 1488 } |
| 1390 | 1489 |
| 1391 ContentSecurityPolicy::ContentSecurityPolicy(ExecutionContextClient* client) | 1490 ContentSecurityPolicy::ContentSecurityPolicy(ExecutionContextClient* client) |
| 1392 : m_client(client) | 1491 : m_client(client) |
| 1393 , m_overrideInlineStyleAllowed(false) | 1492 , m_overrideInlineStyleAllowed(false) |
| 1493 , m_sourceHashAlgorithmsUsed(HashAlgorithmsNone) |
| 1394 { | 1494 { |
| 1395 } | 1495 } |
| 1396 | 1496 |
| 1397 ContentSecurityPolicy::~ContentSecurityPolicy() | 1497 ContentSecurityPolicy::~ContentSecurityPolicy() |
| 1398 { | 1498 { |
| 1399 } | 1499 } |
| 1400 | 1500 |
| 1401 void ContentSecurityPolicy::copyStateFrom(const ContentSecurityPolicy* other) | 1501 void ContentSecurityPolicy::copyStateFrom(const ContentSecurityPolicy* other) |
| 1402 { | 1502 { |
| 1403 ASSERT(m_policies.isEmpty()); | 1503 ASSERT(m_policies.isEmpty()); |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1511 | 1611 |
| 1512 template<bool (CSPDirectiveList::*allowed)(const String&) const> | 1612 template<bool (CSPDirectiveList::*allowed)(const String&) const> |
| 1513 bool isAllowedByAllWithNonce(const CSPDirectiveListVector& policies, const Strin
g& nonce) | 1613 bool isAllowedByAllWithNonce(const CSPDirectiveListVector& policies, const Strin
g& nonce) |
| 1514 { | 1614 { |
| 1515 for (size_t i = 0; i < policies.size(); ++i) { | 1615 for (size_t i = 0; i < policies.size(); ++i) { |
| 1516 if (!(policies[i].get()->*allowed)(nonce)) | 1616 if (!(policies[i].get()->*allowed)(nonce)) |
| 1517 return false; | 1617 return false; |
| 1518 } | 1618 } |
| 1519 return true; | 1619 return true; |
| 1520 } | 1620 } |
| 1621 |
| 1622 template<bool (CSPDirectiveList::*allowed)(const SourceHashValue&) const> |
| 1623 bool isAllowedByAllWithHash(const CSPDirectiveListVector& policies, const Source
HashValue& hashValue) |
| 1624 { |
| 1625 for (size_t i = 0; i < policies.size(); ++i) { |
| 1626 if (!(policies[i].get()->*allowed)(hashValue)) |
| 1627 return false; |
| 1628 } |
| 1629 return true; |
| 1630 } |
| 1631 |
| 1521 template<bool (CSPDirectiveList::*allowFromURL)(const KURL&, ContentSecurityPoli
cy::ReportingStatus) const> | 1632 template<bool (CSPDirectiveList::*allowFromURL)(const KURL&, ContentSecurityPoli
cy::ReportingStatus) const> |
| 1522 bool isAllowedByAllWithURL(const CSPDirectiveListVector& policies, const KURL& u
rl, ContentSecurityPolicy::ReportingStatus reportingStatus) | 1633 bool isAllowedByAllWithURL(const CSPDirectiveListVector& policies, const KURL& u
rl, ContentSecurityPolicy::ReportingStatus reportingStatus) |
| 1523 { | 1634 { |
| 1524 if (SchemeRegistry::schemeShouldBypassContentSecurityPolicy(url.protocol())) | 1635 if (SchemeRegistry::schemeShouldBypassContentSecurityPolicy(url.protocol())) |
| 1525 return true; | 1636 return true; |
| 1526 | 1637 |
| 1527 for (size_t i = 0; i < policies.size(); ++i) { | 1638 for (size_t i = 0; i < policies.size(); ++i) { |
| 1528 if (!(policies[i].get()->*allowFromURL)(url, reportingStatus)) | 1639 if (!(policies[i].get()->*allowFromURL)(url, reportingStatus)) |
| 1529 return false; | 1640 return false; |
| 1530 } | 1641 } |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1584 bool ContentSecurityPolicy::allowScriptNonce(const String& nonce) const | 1695 bool ContentSecurityPolicy::allowScriptNonce(const String& nonce) const |
| 1585 { | 1696 { |
| 1586 return isAllowedByAllWithNonce<&CSPDirectiveList::allowScriptNonce>(m_polici
es, nonce); | 1697 return isAllowedByAllWithNonce<&CSPDirectiveList::allowScriptNonce>(m_polici
es, nonce); |
| 1587 } | 1698 } |
| 1588 | 1699 |
| 1589 bool ContentSecurityPolicy::allowStyleNonce(const String& nonce) const | 1700 bool ContentSecurityPolicy::allowStyleNonce(const String& nonce) const |
| 1590 { | 1701 { |
| 1591 return isAllowedByAllWithNonce<&CSPDirectiveList::allowStyleNonce>(m_policie
s, nonce); | 1702 return isAllowedByAllWithNonce<&CSPDirectiveList::allowStyleNonce>(m_policie
s, nonce); |
| 1592 } | 1703 } |
| 1593 | 1704 |
| 1705 bool ContentSecurityPolicy::allowScriptHash(const String& source) const |
| 1706 { |
| 1707 // TODO(jww) We don't currently have a WTF SHA256 implementation. Once we |
| 1708 // have that, we should implement a proper check for sha256 hash values here
. |
| 1709 if (HashAlgorithmsSha1 & m_sourceHashAlgorithmsUsed) { |
| 1710 Vector<uint8_t, 20> digest; |
| 1711 SHA1 sourceSha1; |
| 1712 sourceSha1.addBytes(UTF8Encoding().normalizeAndEncode(source, WTF::Entit
iesForUnencodables)); |
| 1713 sourceSha1.computeHash(digest); |
| 1714 |
| 1715 if (isAllowedByAllWithHash<&CSPDirectiveList::allowScriptHash>(m_policie
s, SourceHashValue(HashAlgorithmsSha1, Vector<uint8_t>(digest)))) |
| 1716 return true; |
| 1717 } |
| 1718 |
| 1719 return false; |
| 1720 } |
| 1721 |
| 1722 void ContentSecurityPolicy::usesScriptHashAlgorithms(uint8_t algorithms) |
| 1723 { |
| 1724 m_sourceHashAlgorithmsUsed |= algorithms; |
| 1725 } |
| 1726 |
| 1594 bool ContentSecurityPolicy::allowObjectFromSource(const KURL& url, ContentSecuri
tyPolicy::ReportingStatus reportingStatus) const | 1727 bool ContentSecurityPolicy::allowObjectFromSource(const KURL& url, ContentSecuri
tyPolicy::ReportingStatus reportingStatus) const |
| 1595 { | 1728 { |
| 1596 return isAllowedByAllWithURL<&CSPDirectiveList::allowObjectFromSource>(m_pol
icies, url, reportingStatus); | 1729 return isAllowedByAllWithURL<&CSPDirectiveList::allowObjectFromSource>(m_pol
icies, url, reportingStatus); |
| 1597 } | 1730 } |
| 1598 | 1731 |
| 1599 bool ContentSecurityPolicy::allowChildFrameFromSource(const KURL& url, ContentSe
curityPolicy::ReportingStatus reportingStatus) const | 1732 bool ContentSecurityPolicy::allowChildFrameFromSource(const KURL& url, ContentSe
curityPolicy::ReportingStatus reportingStatus) const |
| 1600 { | 1733 { |
| 1601 return isAllowedByAllWithURL<&CSPDirectiveList::allowChildFrameFromSource>(m
_policies, url, reportingStatus); | 1734 return isAllowedByAllWithURL<&CSPDirectiveList::allowChildFrameFromSource>(m
_policies, url, reportingStatus); |
| 1602 } | 1735 } |
| 1603 | 1736 |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1839 { | 1972 { |
| 1840 ASSERT(invalidChar == '#' || invalidChar == '?'); | 1973 ASSERT(invalidChar == '#' || invalidChar == '?'); |
| 1841 | 1974 |
| 1842 String ignoring = "The fragment identifier, including the '#', will be ignor
ed."; | 1975 String ignoring = "The fragment identifier, including the '#', will be ignor
ed."; |
| 1843 if (invalidChar == '?') | 1976 if (invalidChar == '?') |
| 1844 ignoring = "The query component, including the '?', will be ignored."; | 1977 ignoring = "The query component, including the '?', will be ignored."; |
| 1845 String message = "The source list for Content Security Policy directive '" +
directiveName + "' contains a source with an invalid path: '" + value + "'. " +
ignoring; | 1978 String message = "The source list for Content Security Policy directive '" +
directiveName + "' contains a source with an invalid path: '" + value + "'. " +
ignoring; |
| 1846 logToConsole(message); | 1979 logToConsole(message); |
| 1847 } | 1980 } |
| 1848 | 1981 |
| 1849 void ContentSecurityPolicy::reportInvalidNonce(const String& nonce) const | |
| 1850 { | |
| 1851 String message = "Ignoring invalid Content Security Policy script nonce: '"
+ nonce + "'.\n"; | |
| 1852 logToConsole(message); | |
| 1853 } | |
| 1854 | |
| 1855 void ContentSecurityPolicy::reportInvalidSourceExpression(const String& directiv
eName, const String& source) const | 1982 void ContentSecurityPolicy::reportInvalidSourceExpression(const String& directiv
eName, const String& source) const |
| 1856 { | 1983 { |
| 1857 String message = "The source list for Content Security Policy directive '" +
directiveName + "' contains an invalid source: '" + source + "'. It will be ign
ored."; | 1984 String message = "The source list for Content Security Policy directive '" +
directiveName + "' contains an invalid source: '" + source + "'. It will be ign
ored."; |
| 1858 if (equalIgnoringCase(source, "'none'")) | 1985 if (equalIgnoringCase(source, "'none'")) |
| 1859 message = message + " Note that 'none' has no effect unless it is the on
ly expression in the source list."; | 1986 message = message + " Note that 'none' has no effect unless it is the on
ly expression in the source list."; |
| 1860 logToConsole(message); | 1987 logToConsole(message); |
| 1861 } | 1988 } |
| 1862 | 1989 |
| 1863 void ContentSecurityPolicy::reportMissingReportURI(const String& policy) const | 1990 void ContentSecurityPolicy::reportMissingReportURI(const String& policy) const |
| 1864 { | 1991 { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1895 // Collisions have no security impact, so we can save space by storing only
the string's hash rather than the whole report. | 2022 // Collisions have no security impact, so we can save space by storing only
the string's hash rather than the whole report. |
| 1896 return !m_violationReportsSent.contains(report.impl()->hash()); | 2023 return !m_violationReportsSent.contains(report.impl()->hash()); |
| 1897 } | 2024 } |
| 1898 | 2025 |
| 1899 void ContentSecurityPolicy::didSendViolationReport(const String& report) | 2026 void ContentSecurityPolicy::didSendViolationReport(const String& report) |
| 1900 { | 2027 { |
| 1901 m_violationReportsSent.add(report.impl()->hash()); | 2028 m_violationReportsSent.add(report.impl()->hash()); |
| 1902 } | 2029 } |
| 1903 | 2030 |
| 1904 } // namespace WebCore | 2031 } // namespace WebCore |
| OLD | NEW |