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 |