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 26 matching lines...) Expand all Loading... | |
37 #include "core/inspector/ScriptCallStack.h" | 37 #include "core/inspector/ScriptCallStack.h" |
38 #include "core/loader/DocumentLoader.h" | 38 #include "core/loader/DocumentLoader.h" |
39 #include "core/loader/PingLoader.h" | 39 #include "core/loader/PingLoader.h" |
40 #include "core/frame/ContentSecurityPolicyResponseHeaders.h" | 40 #include "core/frame/ContentSecurityPolicyResponseHeaders.h" |
41 #include "core/frame/Frame.h" | 41 #include "core/frame/Frame.h" |
42 #include "core/page/UseCounter.h" | 42 #include "core/page/UseCounter.h" |
43 #include "core/platform/ParsingUtilities.h" | 43 #include "core/platform/ParsingUtilities.h" |
44 #include "core/platform/network/FormData.h" | 44 #include "core/platform/network/FormData.h" |
45 #include "core/platform/network/ResourceResponse.h" | 45 #include "core/platform/network/ResourceResponse.h" |
46 #include "platform/JSONValues.h" | 46 #include "platform/JSONValues.h" |
47 #include "platform/NotImplemented.h" | |
47 #include "weborigin/KURL.h" | 48 #include "weborigin/KURL.h" |
48 #include "weborigin/KnownPorts.h" | 49 #include "weborigin/KnownPorts.h" |
49 #include "weborigin/SchemeRegistry.h" | 50 #include "weborigin/SchemeRegistry.h" |
50 #include "weborigin/SecurityOrigin.h" | 51 #include "weborigin/SecurityOrigin.h" |
51 #include "wtf/HashSet.h" | 52 #include "wtf/HashSet.h" |
53 #include "wtf/SHA1.h" | |
54 #include "wtf/StringHasher.h" | |
55 #include "wtf/text/Base64.h" | |
56 #include "wtf/text/StringBuilder.h" | |
52 #include "wtf/text/TextPosition.h" | 57 #include "wtf/text/TextPosition.h" |
53 #include "wtf/text/WTFString.h" | 58 #include "wtf/text/WTFString.h" |
54 | 59 |
60 namespace WTF { | |
61 | |
62 struct VectorIntHash { | |
63 static unsigned hash(const Vector<uint8_t>& v) { return StringHasher::comput eHash(v.data(), v.size()); } | |
64 static bool equal(const Vector<uint8_t>& a, const Vector<uint8_t>& b) { retu rn a == b; }; | |
65 static const bool safeToCompareToEmptyOrDeleted = true; | |
66 }; | |
67 template<> struct DefaultHash<Vector<uint8_t> > { | |
68 typedef VectorIntHash Hash; | |
69 }; | |
70 | |
71 } // namespace WTF | |
72 | |
55 namespace WebCore { | 73 namespace WebCore { |
56 | 74 |
75 typedef std::pair<unsigned, Vector<uint8_t> > SourceHashValue; | |
76 | |
57 // Normally WebKit uses "static" for internal linkage, but using "static" for | 77 // Normally WebKit uses "static" for internal linkage, but using "static" for |
58 // these functions causes a compile error because these functions are used as | 78 // these functions causes a compile error because these functions are used as |
59 // template parameters. | 79 // template parameters. |
60 namespace { | 80 namespace { |
61 | 81 |
62 bool isDirectiveNameCharacter(UChar c) | 82 bool isDirectiveNameCharacter(UChar c) |
63 { | 83 { |
64 return isASCIIAlphanumeric(c) || c == '-'; | 84 return isASCIIAlphanumeric(c) || c == '-'; |
65 } | 85 } |
66 | 86 |
67 bool isDirectiveValueCharacter(UChar c) | 87 bool isDirectiveValueCharacter(UChar c) |
68 { | 88 { |
69 return isASCIISpace(c) || (c >= 0x21 && c <= 0x7e); // Whitespace + VCHAR | 89 return isASCIISpace(c) || (c >= 0x21 && c <= 0x7e); // Whitespace + VCHAR |
70 } | 90 } |
71 | 91 |
72 bool isNonceCharacter(UChar c) | 92 // Only checks for general Base64 encoded chars, not '=' chars since '=' is |
93 // positional and may only appear at the end of a Base64 encoded string. | |
94 bool isBase64EncodedCharacter(UChar c) | |
73 { | 95 { |
74 return isASCIIAlphanumeric(c) || c == '+' || c == '/'; | 96 return isASCIIAlphanumeric(c) || c == '+' || c == '/'; |
75 } | 97 } |
76 | 98 |
77 bool isSourceCharacter(UChar c) | 99 bool isSourceCharacter(UChar c) |
78 { | 100 { |
79 return !isASCIISpace(c); | 101 return !isASCIISpace(c); |
80 } | 102 } |
81 | 103 |
82 bool isPathComponentCharacter(UChar c) | 104 bool isPathComponentCharacter(UChar c) |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
272 class CSPSourceList { | 294 class CSPSourceList { |
273 public: | 295 public: |
274 CSPSourceList(ContentSecurityPolicy*, const String& directiveName); | 296 CSPSourceList(ContentSecurityPolicy*, const String& directiveName); |
275 | 297 |
276 void parse(const UChar* begin, const UChar* end); | 298 void parse(const UChar* begin, const UChar* end); |
277 | 299 |
278 bool matches(const KURL&); | 300 bool matches(const KURL&); |
279 bool allowInline() const { return m_allowInline; } | 301 bool allowInline() const { return m_allowInline; } |
280 bool allowEval() const { return m_allowEval; } | 302 bool allowEval() const { return m_allowEval; } |
281 bool allowNonce(const String& nonce) const { return !nonce.isNull() && m_non ces.contains(nonce); } | 303 bool allowNonce(const String& nonce) const { return !nonce.isNull() && m_non ces.contains(nonce); } |
304 bool allowHash(const SourceHashValue& hashValue) const { return m_hashes.con tains(hashValue); } | |
305 uint8_t hashFunctionsUsed() const { return m_hashFunctionsUsed; } | |
282 | 306 |
283 private: | 307 private: |
284 bool parseSource(const UChar* begin, const UChar* end, String& scheme, Strin g& host, int& port, String& path, bool& hostHasWildcard, bool& portHasWildcard); | 308 bool parseSource(const UChar* begin, const UChar* end, String& scheme, Strin g& host, int& port, String& path, bool& hostHasWildcard, bool& portHasWildcard); |
285 bool parseScheme(const UChar* begin, const UChar* end, String& scheme); | 309 bool parseScheme(const UChar* begin, const UChar* end, String& scheme); |
286 bool parseHost(const UChar* begin, const UChar* end, String& host, bool& hos tHasWildcard); | 310 bool parseHost(const UChar* begin, const UChar* end, String& host, bool& hos tHasWildcard); |
287 bool parsePort(const UChar* begin, const UChar* end, int& port, bool& portHa sWildcard); | 311 bool parsePort(const UChar* begin, const UChar* end, int& port, bool& portHa sWildcard); |
288 bool parsePath(const UChar* begin, const UChar* end, String& path); | 312 bool parsePath(const UChar* begin, const UChar* end, String& path); |
289 bool parseNonce(const UChar* begin, const UChar* end, String& nonce); | 313 bool parseNonce(const UChar* begin, const UChar* end, String& nonce); |
314 bool parseHash(const UChar* begin, const UChar* end, Vector<uint8_t>& hash, ContentSecurityPolicy::HashFunctions&); | |
290 | 315 |
291 void addSourceSelf(); | 316 void addSourceSelf(); |
292 void addSourceStar(); | 317 void addSourceStar(); |
293 void addSourceUnsafeInline(); | 318 void addSourceUnsafeInline(); |
294 void addSourceUnsafeEval(); | 319 void addSourceUnsafeEval(); |
295 void addSourceNonce(const String& nonce); | 320 void addSourceNonce(const String& nonce); |
321 void addSourceHash(const Vector<uint8_t>& hash, const ContentSecurityPolicy: :HashFunctions&); | |
296 | 322 |
297 ContentSecurityPolicy* m_policy; | 323 ContentSecurityPolicy* m_policy; |
298 Vector<CSPSource> m_list; | 324 Vector<CSPSource> m_list; |
299 String m_directiveName; | 325 String m_directiveName; |
300 bool m_allowStar; | 326 bool m_allowStar; |
301 bool m_allowInline; | 327 bool m_allowInline; |
302 bool m_allowEval; | 328 bool m_allowEval; |
303 HashSet<String> m_nonces; | 329 HashSet<String> m_nonces; |
330 HashSet<SourceHashValue> m_hashes; | |
331 uint8_t m_hashFunctionsUsed; | |
304 }; | 332 }; |
305 | 333 |
306 CSPSourceList::CSPSourceList(ContentSecurityPolicy* policy, const String& direct iveName) | 334 CSPSourceList::CSPSourceList(ContentSecurityPolicy* policy, const String& direct iveName) |
307 : m_policy(policy) | 335 : m_policy(policy) |
308 , m_directiveName(directiveName) | 336 , m_directiveName(directiveName) |
309 , m_allowStar(false) | 337 , m_allowStar(false) |
310 , m_allowInline(false) | 338 , m_allowInline(false) |
311 , m_allowEval(false) | 339 , m_allowEval(false) |
340 , m_hashFunctionsUsed(0) | |
312 { | 341 { |
313 } | 342 } |
314 | 343 |
315 bool CSPSourceList::matches(const KURL& url) | 344 bool CSPSourceList::matches(const KURL& url) |
316 { | 345 { |
317 if (m_allowStar) | 346 if (m_allowStar) |
318 return true; | 347 return true; |
319 | 348 |
320 KURL effectiveURL = SecurityOrigin::shouldUseInnerURL(url) ? SecurityOrigin: :extractInnerURL(url) : url; | 349 KURL effectiveURL = SecurityOrigin::shouldUseInnerURL(url) ? SecurityOrigin: :extractInnerURL(url) : url; |
321 | 350 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
402 | 431 |
403 if (m_policy->experimentalFeaturesEnabled()) { | 432 if (m_policy->experimentalFeaturesEnabled()) { |
404 String nonce; | 433 String nonce; |
405 if (!parseNonce(begin, end, nonce)) | 434 if (!parseNonce(begin, end, nonce)) |
406 return false; | 435 return false; |
407 | 436 |
408 if (!nonce.isNull()) { | 437 if (!nonce.isNull()) { |
409 addSourceNonce(nonce); | 438 addSourceNonce(nonce); |
410 return true; | 439 return true; |
411 } | 440 } |
441 | |
442 Vector<uint8_t> hash; | |
443 ContentSecurityPolicy::HashFunctions hashFunction = ContentSecurityPolic y::HashFunctionsNone; | |
abarth-chromium
2013/10/29 05:56:26
Maybe HashAlgorithms instead of HashFunctions? Th
jww
2013/10/29 17:47:04
Done.
| |
444 if (!parseHash(begin, end, hash, hashFunction)) | |
445 return false; | |
446 | |
447 if (hash.size() > 0) { | |
448 addSourceHash(hash, hashFunction); | |
449 return true; | |
450 } | |
412 } | 451 } |
413 | 452 |
414 const UChar* position = begin; | 453 const UChar* position = begin; |
415 const UChar* beginHost = begin; | 454 const UChar* beginHost = begin; |
416 const UChar* beginPath = end; | 455 const UChar* beginPath = end; |
417 const UChar* beginPort = 0; | 456 const UChar* beginPort = 0; |
418 | 457 |
419 skipWhile<UChar, isNotColonOrSlash>(position, end); | 458 skipWhile<UChar, isNotColonOrSlash>(position, end); |
420 | 459 |
421 if (position == end) { | 460 if (position == end) { |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
491 bool CSPSourceList::parseNonce(const UChar* begin, const UChar* end, String& non ce) | 530 bool CSPSourceList::parseNonce(const UChar* begin, const UChar* end, String& non ce) |
492 { | 531 { |
493 DEFINE_STATIC_LOCAL(const String, noncePrefix, ("'nonce-")); | 532 DEFINE_STATIC_LOCAL(const String, noncePrefix, ("'nonce-")); |
494 | 533 |
495 if (!equalIgnoringCase(noncePrefix.characters8(), begin, noncePrefix.length( ))) | 534 if (!equalIgnoringCase(noncePrefix.characters8(), begin, noncePrefix.length( ))) |
496 return true; | 535 return true; |
497 | 536 |
498 const UChar* position = begin + noncePrefix.length(); | 537 const UChar* position = begin + noncePrefix.length(); |
499 const UChar* nonceBegin = position; | 538 const UChar* nonceBegin = position; |
500 | 539 |
501 skipWhile<UChar, isNonceCharacter>(position, end); | 540 skipWhile<UChar, isBase64EncodedCharacter>(position, end); |
502 ASSERT(nonceBegin <= position); | 541 ASSERT(nonceBegin <= position); |
503 | 542 |
504 if (((position + 1) != end && *position != '\'') || !(position - nonceBegin )) | 543 if ((position + 1) != end || *position != '\'' || !(position - nonceBegin)) |
505 return false; | 544 return false; |
506 | 545 |
507 nonce = String(nonceBegin, position - nonceBegin); | 546 nonce = String(nonceBegin, position - nonceBegin); |
508 return true; | 547 return true; |
509 } | 548 } |
510 | 549 |
550 // hash-source = "'" hash-algorithm "-" hash-value "'" | |
551 // hash-algorithm = "sha1" / "sha256" | |
552 // hash-value = 1*( ALPHA / DIGIT / "+" / "/" / "=" ) | |
553 // | |
554 bool CSPSourceList::parseHash(const UChar* begin, const UChar* end, Vector<uint8 _t>& hash, ContentSecurityPolicy::HashFunctions& hashFunction) | |
555 { | |
556 DEFINE_STATIC_LOCAL(const String, sha1Prefix, ("'sha1-")); | |
557 DEFINE_STATIC_LOCAL(const String, sha256Prefix, ("'sha256-")); | |
558 | |
559 String prefix; | |
560 if (equalIgnoringCase(sha1Prefix.characters8(), begin, sha1Prefix.length())) { | |
561 prefix = sha1Prefix; | |
562 hashFunction = ContentSecurityPolicy::HashFunctionsSha1; | |
563 } else if (equalIgnoringCase(sha256Prefix.characters8(), begin, sha256Prefix .length())) { | |
564 notImplemented(); | |
565 } else { | |
566 return true; | |
567 } | |
568 | |
569 const UChar* position = begin + prefix.length(); | |
570 const UChar* hashBegin = position; | |
571 | |
572 skipWhile<UChar, isBase64EncodedCharacter>(position, end); | |
573 ASSERT(hashBegin <= position); | |
574 | |
575 // Base64 encodings may end with exactly one or two '=' characters | |
576 skipExactly<UChar>(position, position + 1, '='); | |
577 skipExactly<UChar>(position, position + 1, '='); | |
578 | |
579 if ((position + 1) != end || *position != '\'' || !(position - hashBegin)) | |
580 return false; | |
581 | |
582 Vector<char> hashVector; | |
583 base64Decode(String(hashBegin, position - hashBegin), hashVector); | |
abarth-chromium
2013/10/29 05:56:26
It's lame that we need to copy these characters in
jww
2013/10/29 17:47:04
Okay, I changed this by adding a new base64Decode
| |
584 hash.append(reinterpret_cast<uint8_t*>(hashVector.data()), hashVector.size() ); | |
585 return true; | |
586 } | |
587 | |
511 // ; <scheme> production from RFC 3986 | 588 // ; <scheme> production from RFC 3986 |
512 // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) | 589 // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) |
513 // | 590 // |
514 bool CSPSourceList::parseScheme(const UChar* begin, const UChar* end, String& sc heme) | 591 bool CSPSourceList::parseScheme(const UChar* begin, const UChar* end, String& sc heme) |
515 { | 592 { |
516 ASSERT(begin <= end); | 593 ASSERT(begin <= end); |
517 ASSERT(scheme.isEmpty()); | 594 ASSERT(scheme.isEmpty()); |
518 | 595 |
519 if (begin == end) | 596 if (begin == end) |
520 return false; | 597 return false; |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
643 void CSPSourceList::addSourceUnsafeEval() | 720 void CSPSourceList::addSourceUnsafeEval() |
644 { | 721 { |
645 m_allowEval = true; | 722 m_allowEval = true; |
646 } | 723 } |
647 | 724 |
648 void CSPSourceList::addSourceNonce(const String& nonce) | 725 void CSPSourceList::addSourceNonce(const String& nonce) |
649 { | 726 { |
650 m_nonces.add(nonce); | 727 m_nonces.add(nonce); |
651 } | 728 } |
652 | 729 |
730 void CSPSourceList::addSourceHash(const Vector<uint8_t>& hash, const ContentSecu rityPolicy::HashFunctions& hashFunction) | |
731 { | |
732 m_hashes.add(SourceHashValue(hashFunction, hash)); | |
abarth-chromium
2013/10/29 05:56:26
It's slightly ugly that you've reversed the order
jww
2013/10/29 17:47:04
Done.
| |
733 m_hashFunctionsUsed |= hashFunction; | |
734 } | |
735 | |
653 class CSPDirective { | 736 class CSPDirective { |
654 public: | 737 public: |
655 CSPDirective(const String& name, const String& value, ContentSecurityPolicy* policy) | 738 CSPDirective(const String& name, const String& value, ContentSecurityPolicy* policy) |
656 : m_name(name) | 739 : m_name(name) |
657 , m_text(name + ' ' + value) | 740 , m_text(name + ' ' + value) |
658 , m_policy(policy) | 741 , m_policy(policy) |
659 { | 742 { |
660 } | 743 } |
661 | 744 |
662 const String& text() const { return m_text; } | 745 const String& text() const { return m_text; } |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
759 } | 842 } |
760 | 843 |
761 bool allows(const KURL& url) | 844 bool allows(const KURL& url) |
762 { | 845 { |
763 return m_sourceList.matches(url.isEmpty() ? policy()->url() : url); | 846 return m_sourceList.matches(url.isEmpty() ? policy()->url() : url); |
764 } | 847 } |
765 | 848 |
766 bool allowInline() const { return m_sourceList.allowInline(); } | 849 bool allowInline() const { return m_sourceList.allowInline(); } |
767 bool allowEval() const { return m_sourceList.allowEval(); } | 850 bool allowEval() const { return m_sourceList.allowEval(); } |
768 bool allowNonce(const String& nonce) const { return m_sourceList.allowNonce( nonce.stripWhiteSpace()); } | 851 bool allowNonce(const String& nonce) const { return m_sourceList.allowNonce( nonce.stripWhiteSpace()); } |
852 bool allowHash(const SourceHashValue& hashValue) const { return m_sourceList .allowHash(hashValue); } | |
853 | |
854 uint8_t hashFunctionsUsed() const { return m_sourceList.hashFunctionsUsed(); } | |
769 | 855 |
770 private: | 856 private: |
771 CSPSourceList m_sourceList; | 857 CSPSourceList m_sourceList; |
772 }; | 858 }; |
773 | 859 |
774 class CSPDirectiveList { | 860 class CSPDirectiveList { |
775 WTF_MAKE_FAST_ALLOCATED; | 861 WTF_MAKE_FAST_ALLOCATED; |
776 public: | 862 public: |
777 static PassOwnPtr<CSPDirectiveList> create(ContentSecurityPolicy*, const UCh ar* begin, const UChar* end, ContentSecurityPolicy::HeaderType); | 863 static PassOwnPtr<CSPDirectiveList> create(ContentSecurityPolicy*, const UCh ar* begin, const UChar* end, ContentSecurityPolicy::HeaderType); |
778 | 864 |
(...skipping 14 matching lines...) Expand all Loading... | |
793 bool allowChildFrameFromSource(const KURL&, ContentSecurityPolicy::Reporting Status) const; | 879 bool allowChildFrameFromSource(const KURL&, ContentSecurityPolicy::Reporting Status) const; |
794 bool allowImageFromSource(const KURL&, ContentSecurityPolicy::ReportingStatu s) const; | 880 bool allowImageFromSource(const KURL&, ContentSecurityPolicy::ReportingStatu s) const; |
795 bool allowStyleFromSource(const KURL&, ContentSecurityPolicy::ReportingStatu s) const; | 881 bool allowStyleFromSource(const KURL&, ContentSecurityPolicy::ReportingStatu s) const; |
796 bool allowFontFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus ) const; | 882 bool allowFontFromSource(const KURL&, ContentSecurityPolicy::ReportingStatus ) const; |
797 bool allowMediaFromSource(const KURL&, ContentSecurityPolicy::ReportingStatu s) const; | 883 bool allowMediaFromSource(const KURL&, ContentSecurityPolicy::ReportingStatu s) const; |
798 bool allowConnectToSource(const KURL&, ContentSecurityPolicy::ReportingStatu s) const; | 884 bool allowConnectToSource(const KURL&, ContentSecurityPolicy::ReportingStatu s) const; |
799 bool allowFormAction(const KURL&, ContentSecurityPolicy::ReportingStatus) co nst; | 885 bool allowFormAction(const KURL&, ContentSecurityPolicy::ReportingStatus) co nst; |
800 bool allowBaseURI(const KURL&, ContentSecurityPolicy::ReportingStatus) const ; | 886 bool allowBaseURI(const KURL&, ContentSecurityPolicy::ReportingStatus) const ; |
801 bool allowScriptNonce(const String&) const; | 887 bool allowScriptNonce(const String&) const; |
802 bool allowStyleNonce(const String&) const; | 888 bool allowStyleNonce(const String&) const; |
889 bool allowScriptHash(const SourceHashValue&) const; | |
803 | 890 |
804 void gatherReportURIs(DOMStringList&) const; | 891 void gatherReportURIs(DOMStringList&) const; |
805 const String& evalDisabledErrorMessage() const { return m_evalDisabledErrorM essage; } | 892 const String& evalDisabledErrorMessage() const { return m_evalDisabledErrorM essage; } |
806 ReflectedXSSDisposition reflectedXSSDisposition() const { return m_reflected XSSDisposition; } | 893 ReflectedXSSDisposition reflectedXSSDisposition() const { return m_reflected XSSDisposition; } |
807 bool isReportOnly() const { return m_reportOnly; } | 894 bool isReportOnly() const { return m_reportOnly; } |
808 const Vector<KURL>& reportURIs() const { return m_reportURIs; } | 895 const Vector<KURL>& reportURIs() const { return m_reportURIs; } |
809 | 896 |
810 private: | 897 private: |
811 CSPDirectiveList(ContentSecurityPolicy*, ContentSecurityPolicy::HeaderType); | 898 CSPDirectiveList(ContentSecurityPolicy*, ContentSecurityPolicy::HeaderType); |
812 | 899 |
813 bool parseDirective(const UChar* begin, const UChar* end, String& name, Stri ng& value); | 900 bool parseDirective(const UChar* begin, const UChar* end, String& name, Stri ng& value); |
814 void parseReportURI(const String& name, const String& value); | 901 void parseReportURI(const String& name, const String& value); |
815 void parsePluginTypes(const String& name, const String& value); | 902 void parsePluginTypes(const String& name, const String& value); |
816 void parseReflectedXSS(const String& name, const String& value); | 903 void parseReflectedXSS(const String& name, const String& value); |
817 void addDirective(const String& name, const String& value); | 904 void addDirective(const String& name, const String& value); |
818 void applySandboxPolicy(const String& name, const String& sandboxPolicy); | 905 void applySandboxPolicy(const String& name, const String& sandboxPolicy); |
819 | 906 |
820 template <class CSPDirectiveType> | 907 template <class CSPDirectiveType> |
821 void setCSPDirective(const String& name, const String& value, OwnPtr<CSPDire ctiveType>&); | 908 void setCSPDirective(const String& name, const String& value, OwnPtr<CSPDire ctiveType>&); |
822 | 909 |
823 SourceListDirective* operativeDirective(SourceListDirective*) const; | 910 SourceListDirective* operativeDirective(SourceListDirective*) const; |
824 void reportViolation(const String& directiveText, const String& effectiveDir ective, const String& consoleMessage, const KURL& blockedURL) const; | 911 void reportViolation(const String& directiveText, const String& effectiveDir ective, const String& consoleMessage, const KURL& blockedURL) const; |
825 void reportViolationWithLocation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const String& contextURL, const WTF::OrdinalNumber& contextLine) const; | 912 void reportViolationWithLocation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const KURL& blockedURL, const String& contextURL, const WTF::OrdinalNumber& contextLine) const; |
826 void reportViolationWithState(const String& directiveText, const String& eff ectiveDirective, const String& consoleMessage, const KURL& blockedURL, ScriptSta te*) const; | 913 void reportViolationWithState(const String& directiveText, const String& eff ectiveDirective, const String& consoleMessage, const KURL& blockedURL, ScriptSta te*) const; |
827 | 914 |
828 bool checkEval(SourceListDirective*) const; | 915 bool checkEval(SourceListDirective*) const; |
829 bool checkInline(SourceListDirective*) const; | 916 bool checkInline(SourceListDirective*) const; |
830 bool checkNonce(SourceListDirective*, const String&) const; | 917 bool checkNonce(SourceListDirective*, const String&) const; |
918 bool checkHash(SourceListDirective*, const SourceHashValue&) const; | |
831 bool checkSource(SourceListDirective*, const KURL&) const; | 919 bool checkSource(SourceListDirective*, const KURL&) const; |
832 bool checkMediaType(MediaListDirective*, const String& type, const String& t ypeAttribute) const; | 920 bool checkMediaType(MediaListDirective*, const String& type, const String& t ypeAttribute) const; |
833 | 921 |
834 void setEvalDisabledErrorMessage(const String& errorMessage) { m_evalDisable dErrorMessage = errorMessage; } | 922 void setEvalDisabledErrorMessage(const String& errorMessage) { m_evalDisable dErrorMessage = errorMessage; } |
835 | 923 |
836 bool checkEvalAndReportViolation(SourceListDirective*, const String& console Message, ScriptState*) const; | 924 bool checkEvalAndReportViolation(SourceListDirective*, const String& console Message, ScriptState*) const; |
837 bool checkInlineAndReportViolation(SourceListDirective*, const String& conso leMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine, bool isScript) const; | 925 bool checkInlineAndReportViolation(SourceListDirective*, const String& conso leMessage, const String& contextURL, const WTF::OrdinalNumber& contextLine, bool isScript) const; |
838 | 926 |
839 bool checkSourceAndReportViolation(SourceListDirective*, const KURL&, const String& effectiveDirective) const; | 927 bool checkSourceAndReportViolation(SourceListDirective*, const KURL&, const String& effectiveDirective) const; |
840 bool checkMediaTypeAndReportViolation(MediaListDirective*, const String& typ e, const String& typeAttribute, const String& consoleMessage) const; | 928 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... | |
923 bool CSPDirectiveList::checkInline(SourceListDirective* directive) const | 1011 bool CSPDirectiveList::checkInline(SourceListDirective* directive) const |
924 { | 1012 { |
925 return !directive || directive->allowInline(); | 1013 return !directive || directive->allowInline(); |
926 } | 1014 } |
927 | 1015 |
928 bool CSPDirectiveList::checkNonce(SourceListDirective* directive, const String& nonce) const | 1016 bool CSPDirectiveList::checkNonce(SourceListDirective* directive, const String& nonce) const |
929 { | 1017 { |
930 return !directive || directive->allowNonce(nonce); | 1018 return !directive || directive->allowNonce(nonce); |
931 } | 1019 } |
932 | 1020 |
1021 bool CSPDirectiveList::checkHash(SourceListDirective* directive, const SourceHas hValue& hashValue) const | |
1022 { | |
1023 return !directive || directive->allowHash(hashValue); | |
1024 } | |
1025 | |
933 bool CSPDirectiveList::checkSource(SourceListDirective* directive, const KURL& u rl) const | 1026 bool CSPDirectiveList::checkSource(SourceListDirective* directive, const KURL& u rl) const |
934 { | 1027 { |
935 return !directive || directive->allows(url); | 1028 return !directive || directive->allows(url); |
936 } | 1029 } |
937 | 1030 |
938 bool CSPDirectiveList::checkMediaType(MediaListDirective* directive, const Strin g& type, const String& typeAttribute) const | 1031 bool CSPDirectiveList::checkMediaType(MediaListDirective* directive, const Strin g& type, const String& typeAttribute) const |
939 { | 1032 { |
940 if (!directive) | 1033 if (!directive) |
941 return true; | 1034 return true; |
942 if (typeAttribute.isEmpty() || typeAttribute.stripWhiteSpace() != type) | 1035 if (typeAttribute.isEmpty() || typeAttribute.stripWhiteSpace() != type) |
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1168 bool CSPDirectiveList::allowScriptNonce(const String& nonce) const | 1261 bool CSPDirectiveList::allowScriptNonce(const String& nonce) const |
1169 { | 1262 { |
1170 return checkNonce(operativeDirective(m_scriptSrc.get()), nonce); | 1263 return checkNonce(operativeDirective(m_scriptSrc.get()), nonce); |
1171 } | 1264 } |
1172 | 1265 |
1173 bool CSPDirectiveList::allowStyleNonce(const String& nonce) const | 1266 bool CSPDirectiveList::allowStyleNonce(const String& nonce) const |
1174 { | 1267 { |
1175 return checkNonce(operativeDirective(m_styleSrc.get()), nonce); | 1268 return checkNonce(operativeDirective(m_styleSrc.get()), nonce); |
1176 } | 1269 } |
1177 | 1270 |
1271 bool CSPDirectiveList::allowScriptHash(const SourceHashValue& hashValue) const | |
1272 { | |
1273 return checkHash(operativeDirective(m_scriptSrc.get()), hashValue); | |
1274 } | |
1275 | |
1178 // policy = directive-list | 1276 // policy = directive-list |
1179 // directive-list = [ directive *( ";" [ directive ] ) ] | 1277 // directive-list = [ directive *( ";" [ directive ] ) ] |
1180 // | 1278 // |
1181 void CSPDirectiveList::parse(const UChar* begin, const UChar* end) | 1279 void CSPDirectiveList::parse(const UChar* begin, const UChar* end) |
1182 { | 1280 { |
1183 m_header = String(begin, end - begin); | 1281 m_header = String(begin, end - begin); |
1184 | 1282 |
1185 if (begin == end) | 1283 if (begin == end) |
1186 return; | 1284 return; |
1187 | 1285 |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1351 // value1 value2 | 1449 // value1 value2 |
1352 // ^ | 1450 // ^ |
1353 m_reflectedXSSDisposition = ReflectedXSSInvalid; | 1451 m_reflectedXSSDisposition = ReflectedXSSInvalid; |
1354 m_policy->reportInvalidReflectedXSS(value); | 1452 m_policy->reportInvalidReflectedXSS(value); |
1355 } | 1453 } |
1356 | 1454 |
1357 void CSPDirectiveList::addDirective(const String& name, const String& value) | 1455 void CSPDirectiveList::addDirective(const String& name, const String& value) |
1358 { | 1456 { |
1359 ASSERT(!name.isEmpty()); | 1457 ASSERT(!name.isEmpty()); |
1360 | 1458 |
1361 if (equalIgnoringCase(name, defaultSrc)) | 1459 if (equalIgnoringCase(name, defaultSrc)) { |
1362 setCSPDirective<SourceListDirective>(name, value, m_defaultSrc); | 1460 setCSPDirective<SourceListDirective>(name, value, m_defaultSrc); |
1363 else if (equalIgnoringCase(name, scriptSrc)) | 1461 } else if (equalIgnoringCase(name, scriptSrc)) { |
1364 setCSPDirective<SourceListDirective>(name, value, m_scriptSrc); | 1462 setCSPDirective<SourceListDirective>(name, value, m_scriptSrc); |
1365 else if (equalIgnoringCase(name, objectSrc)) | 1463 m_policy->usesScriptHashFunctions(m_scriptSrc->hashFunctionsUsed()); |
1464 } else if (equalIgnoringCase(name, objectSrc)) { | |
1366 setCSPDirective<SourceListDirective>(name, value, m_objectSrc); | 1465 setCSPDirective<SourceListDirective>(name, value, m_objectSrc); |
1367 else if (equalIgnoringCase(name, frameSrc)) | 1466 } else if (equalIgnoringCase(name, frameSrc)) { |
1368 setCSPDirective<SourceListDirective>(name, value, m_frameSrc); | 1467 setCSPDirective<SourceListDirective>(name, value, m_frameSrc); |
1369 else if (equalIgnoringCase(name, imgSrc)) | 1468 } else if (equalIgnoringCase(name, imgSrc)) { |
1370 setCSPDirective<SourceListDirective>(name, value, m_imgSrc); | 1469 setCSPDirective<SourceListDirective>(name, value, m_imgSrc); |
1371 else if (equalIgnoringCase(name, styleSrc)) | 1470 } else if (equalIgnoringCase(name, styleSrc)) { |
1372 setCSPDirective<SourceListDirective>(name, value, m_styleSrc); | 1471 setCSPDirective<SourceListDirective>(name, value, m_styleSrc); |
1373 else if (equalIgnoringCase(name, fontSrc)) | 1472 } else if (equalIgnoringCase(name, fontSrc)) { |
1374 setCSPDirective<SourceListDirective>(name, value, m_fontSrc); | 1473 setCSPDirective<SourceListDirective>(name, value, m_fontSrc); |
1375 else if (equalIgnoringCase(name, mediaSrc)) | 1474 } else if (equalIgnoringCase(name, mediaSrc)) { |
1376 setCSPDirective<SourceListDirective>(name, value, m_mediaSrc); | 1475 setCSPDirective<SourceListDirective>(name, value, m_mediaSrc); |
1377 else if (equalIgnoringCase(name, connectSrc)) | 1476 } else if (equalIgnoringCase(name, connectSrc)) { |
1378 setCSPDirective<SourceListDirective>(name, value, m_connectSrc); | 1477 setCSPDirective<SourceListDirective>(name, value, m_connectSrc); |
1379 else if (equalIgnoringCase(name, sandbox)) | 1478 } else if (equalIgnoringCase(name, sandbox)) { |
1380 applySandboxPolicy(name, value); | 1479 applySandboxPolicy(name, value); |
1381 else if (equalIgnoringCase(name, reportURI)) | 1480 } else if (equalIgnoringCase(name, reportURI)) { |
1382 parseReportURI(name, value); | 1481 parseReportURI(name, value); |
1383 else if (m_policy->experimentalFeaturesEnabled()) { | 1482 } else if (m_policy->experimentalFeaturesEnabled()) { |
1384 if (equalIgnoringCase(name, baseURI)) | 1483 if (equalIgnoringCase(name, baseURI)) |
1385 setCSPDirective<SourceListDirective>(name, value, m_baseURI); | 1484 setCSPDirective<SourceListDirective>(name, value, m_baseURI); |
1386 else if (equalIgnoringCase(name, formAction)) | 1485 else if (equalIgnoringCase(name, formAction)) |
1387 setCSPDirective<SourceListDirective>(name, value, m_formAction); | 1486 setCSPDirective<SourceListDirective>(name, value, m_formAction); |
1388 else if (equalIgnoringCase(name, pluginTypes)) | 1487 else if (equalIgnoringCase(name, pluginTypes)) |
1389 setCSPDirective<MediaListDirective>(name, value, m_pluginTypes); | 1488 setCSPDirective<MediaListDirective>(name, value, m_pluginTypes); |
1390 else if (equalIgnoringCase(name, reflectedXSS)) | 1489 else if (equalIgnoringCase(name, reflectedXSS)) |
1391 parseReflectedXSS(name, value); | 1490 parseReflectedXSS(name, value); |
1392 else | 1491 else |
1393 m_policy->reportUnsupportedDirective(name); | 1492 m_policy->reportUnsupportedDirective(name); |
1493 } else { | |
1494 m_policy->reportUnsupportedDirective(name); | |
1394 } | 1495 } |
1395 else | |
1396 m_policy->reportUnsupportedDirective(name); | |
1397 } | 1496 } |
1398 | 1497 |
1399 ContentSecurityPolicy::ContentSecurityPolicy(ExecutionContext* executionContext) | 1498 ContentSecurityPolicy::ContentSecurityPolicy(ExecutionContext* executionContext) |
1400 : m_executionContext(executionContext) | 1499 : m_executionContext(executionContext) |
1401 , m_overrideInlineStyleAllowed(false) | 1500 , m_overrideInlineStyleAllowed(false) |
1501 , m_sourceHashFunctionsUsed(HashFunctionsNone) | |
1402 { | 1502 { |
1403 } | 1503 } |
1404 | 1504 |
1405 ContentSecurityPolicy::~ContentSecurityPolicy() | 1505 ContentSecurityPolicy::~ContentSecurityPolicy() |
1406 { | 1506 { |
1407 } | 1507 } |
1408 | 1508 |
1409 void ContentSecurityPolicy::copyStateFrom(const ContentSecurityPolicy* other) | 1509 void ContentSecurityPolicy::copyStateFrom(const ContentSecurityPolicy* other) |
1410 { | 1510 { |
1411 ASSERT(m_policies.isEmpty()); | 1511 ASSERT(m_policies.isEmpty()); |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1517 | 1617 |
1518 template<bool (CSPDirectiveList::*allowed)(const String&) const> | 1618 template<bool (CSPDirectiveList::*allowed)(const String&) const> |
1519 bool isAllowedByAllWithNonce(const CSPDirectiveListVector& policies, const Strin g& nonce) | 1619 bool isAllowedByAllWithNonce(const CSPDirectiveListVector& policies, const Strin g& nonce) |
1520 { | 1620 { |
1521 for (size_t i = 0; i < policies.size(); ++i) { | 1621 for (size_t i = 0; i < policies.size(); ++i) { |
1522 if (!(policies[i].get()->*allowed)(nonce)) | 1622 if (!(policies[i].get()->*allowed)(nonce)) |
1523 return false; | 1623 return false; |
1524 } | 1624 } |
1525 return true; | 1625 return true; |
1526 } | 1626 } |
1627 | |
1628 template<bool (CSPDirectiveList::*allowed)(const SourceHashValue&) const> | |
1629 bool isAllowedByAllWithHash(const CSPDirectiveListVector& policies, const Source HashValue& hashValue) | |
1630 { | |
1631 for (size_t i = 0; i < policies.size(); ++i) { | |
1632 if (!(policies[i].get()->*allowed)(hashValue)) | |
1633 return false; | |
1634 } | |
1635 return true; | |
1636 } | |
1637 | |
1527 template<bool (CSPDirectiveList::*allowFromURL)(const KURL&, ContentSecurityPoli cy::ReportingStatus) const> | 1638 template<bool (CSPDirectiveList::*allowFromURL)(const KURL&, ContentSecurityPoli cy::ReportingStatus) const> |
1528 bool isAllowedByAllWithURL(const CSPDirectiveListVector& policies, const KURL& u rl, ContentSecurityPolicy::ReportingStatus reportingStatus) | 1639 bool isAllowedByAllWithURL(const CSPDirectiveListVector& policies, const KURL& u rl, ContentSecurityPolicy::ReportingStatus reportingStatus) |
1529 { | 1640 { |
1530 if (SchemeRegistry::schemeShouldBypassContentSecurityPolicy(url.protocol())) | 1641 if (SchemeRegistry::schemeShouldBypassContentSecurityPolicy(url.protocol())) |
1531 return true; | 1642 return true; |
1532 | 1643 |
1533 for (size_t i = 0; i < policies.size(); ++i) { | 1644 for (size_t i = 0; i < policies.size(); ++i) { |
1534 if (!(policies[i].get()->*allowFromURL)(url, reportingStatus)) | 1645 if (!(policies[i].get()->*allowFromURL)(url, reportingStatus)) |
1535 return false; | 1646 return false; |
1536 } | 1647 } |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1590 bool ContentSecurityPolicy::allowScriptNonce(const String& nonce) const | 1701 bool ContentSecurityPolicy::allowScriptNonce(const String& nonce) const |
1591 { | 1702 { |
1592 return isAllowedByAllWithNonce<&CSPDirectiveList::allowScriptNonce>(m_polici es, nonce); | 1703 return isAllowedByAllWithNonce<&CSPDirectiveList::allowScriptNonce>(m_polici es, nonce); |
1593 } | 1704 } |
1594 | 1705 |
1595 bool ContentSecurityPolicy::allowStyleNonce(const String& nonce) const | 1706 bool ContentSecurityPolicy::allowStyleNonce(const String& nonce) const |
1596 { | 1707 { |
1597 return isAllowedByAllWithNonce<&CSPDirectiveList::allowStyleNonce>(m_policie s, nonce); | 1708 return isAllowedByAllWithNonce<&CSPDirectiveList::allowStyleNonce>(m_policie s, nonce); |
1598 } | 1709 } |
1599 | 1710 |
1711 bool ContentSecurityPolicy::allowScriptHash(const String& source) const | |
1712 { | |
1713 // TODO(jww) We don't currently have a WTF SHA256 implementation. Once we | |
1714 // have that, we should implement a proper check for sha256 hash values here . | |
1715 if (HashFunctionsSha1 & m_sourceHashFunctionsUsed) { | |
1716 Vector<uint8_t, 20> digest; | |
1717 SHA1 sourceSha1; | |
1718 sourceSha1.addBytes(UTF8Encoding().normalizeAndEncode(source, WTF::Entit iesForUnencodables)); | |
1719 sourceSha1.computeHash(digest); | |
1720 | |
1721 if (isAllowedByAllWithHash<&CSPDirectiveList::allowScriptHash>(m_policie s, SourceHashValue(HashFunctionsSha1, Vector<uint8_t>(digest)))) | |
1722 return true; | |
1723 } | |
1724 | |
1725 return false; | |
1726 } | |
1727 | |
1728 void ContentSecurityPolicy::usesScriptHashFunctions(uint8_t hashFunctions) | |
1729 { | |
1730 m_sourceHashFunctionsUsed |= hashFunctions; | |
1731 } | |
1732 | |
1600 bool ContentSecurityPolicy::allowObjectFromSource(const KURL& url, ContentSecuri tyPolicy::ReportingStatus reportingStatus) const | 1733 bool ContentSecurityPolicy::allowObjectFromSource(const KURL& url, ContentSecuri tyPolicy::ReportingStatus reportingStatus) const |
1601 { | 1734 { |
1602 return isAllowedByAllWithURL<&CSPDirectiveList::allowObjectFromSource>(m_pol icies, url, reportingStatus); | 1735 return isAllowedByAllWithURL<&CSPDirectiveList::allowObjectFromSource>(m_pol icies, url, reportingStatus); |
1603 } | 1736 } |
1604 | 1737 |
1605 bool ContentSecurityPolicy::allowChildFrameFromSource(const KURL& url, ContentSe curityPolicy::ReportingStatus reportingStatus) const | 1738 bool ContentSecurityPolicy::allowChildFrameFromSource(const KURL& url, ContentSe curityPolicy::ReportingStatus reportingStatus) const |
1606 { | 1739 { |
1607 return isAllowedByAllWithURL<&CSPDirectiveList::allowChildFrameFromSource>(m _policies, url, reportingStatus); | 1740 return isAllowedByAllWithURL<&CSPDirectiveList::allowChildFrameFromSource>(m _policies, url, reportingStatus); |
1608 } | 1741 } |
1609 | 1742 |
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1844 { | 1977 { |
1845 ASSERT(invalidChar == '#' || invalidChar == '?'); | 1978 ASSERT(invalidChar == '#' || invalidChar == '?'); |
1846 | 1979 |
1847 String ignoring = "The fragment identifier, including the '#', will be ignor ed."; | 1980 String ignoring = "The fragment identifier, including the '#', will be ignor ed."; |
1848 if (invalidChar == '?') | 1981 if (invalidChar == '?') |
1849 ignoring = "The query component, including the '?', will be ignored."; | 1982 ignoring = "The query component, including the '?', will be ignored."; |
1850 String message = "The source list for Content Security Policy directive '" + directiveName + "' contains a source with an invalid path: '" + value + "'. " + ignoring; | 1983 String message = "The source list for Content Security Policy directive '" + directiveName + "' contains a source with an invalid path: '" + value + "'. " + ignoring; |
1851 logToConsole(message); | 1984 logToConsole(message); |
1852 } | 1985 } |
1853 | 1986 |
1854 void ContentSecurityPolicy::reportInvalidNonce(const String& nonce) const | |
1855 { | |
1856 String message = "Ignoring invalid Content Security Policy script nonce: '" + nonce + "'.\n"; | |
1857 logToConsole(message); | |
1858 } | |
1859 | |
1860 void ContentSecurityPolicy::reportInvalidSourceExpression(const String& directiv eName, const String& source) const | 1987 void ContentSecurityPolicy::reportInvalidSourceExpression(const String& directiv eName, const String& source) const |
1861 { | 1988 { |
1862 String message = "The source list for Content Security Policy directive '" + directiveName + "' contains an invalid source: '" + source + "'. It will be ign ored."; | 1989 String message = "The source list for Content Security Policy directive '" + directiveName + "' contains an invalid source: '" + source + "'. It will be ign ored."; |
1863 if (equalIgnoringCase(source, "'none'")) | 1990 if (equalIgnoringCase(source, "'none'")) |
1864 message = message + " Note that 'none' has no effect unless it is the on ly expression in the source list."; | 1991 message = message + " Note that 'none' has no effect unless it is the on ly expression in the source list."; |
1865 logToConsole(message); | 1992 logToConsole(message); |
1866 } | 1993 } |
1867 | 1994 |
1868 void ContentSecurityPolicy::reportMissingReportURI(const String& policy) const | 1995 void ContentSecurityPolicy::reportMissingReportURI(const String& policy) const |
1869 { | 1996 { |
(...skipping 30 matching lines...) Expand all Loading... | |
1900 // Collisions have no security impact, so we can save space by storing only the string's hash rather than the whole report. | 2027 // Collisions have no security impact, so we can save space by storing only the string's hash rather than the whole report. |
1901 return !m_violationReportsSent.contains(report.impl()->hash()); | 2028 return !m_violationReportsSent.contains(report.impl()->hash()); |
1902 } | 2029 } |
1903 | 2030 |
1904 void ContentSecurityPolicy::didSendViolationReport(const String& report) | 2031 void ContentSecurityPolicy::didSendViolationReport(const String& report) |
1905 { | 2032 { |
1906 m_violationReportsSent.add(report.impl()->hash()); | 2033 m_violationReportsSent.add(report.impl()->hash()); |
1907 } | 2034 } |
1908 | 2035 |
1909 } // namespace WebCore | 2036 } // namespace WebCore |
OLD | NEW |