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 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
91 // https://w3c.github.io/manifest/#content-security-policy | 91 // https://w3c.github.io/manifest/#content-security-policy |
92 const char ContentSecurityPolicy::ManifestSrc[] = "manifest-src"; | 92 const char ContentSecurityPolicy::ManifestSrc[] = "manifest-src"; |
93 | 93 |
94 // Mixed Content Directive | 94 // Mixed Content Directive |
95 // https://w3c.github.io/webappsec/specs/mixedcontent/#strict-mode | 95 // https://w3c.github.io/webappsec/specs/mixedcontent/#strict-mode |
96 const char ContentSecurityPolicy::BlockAllMixedContent[] = "block-all-mixed-cont
ent"; | 96 const char ContentSecurityPolicy::BlockAllMixedContent[] = "block-all-mixed-cont
ent"; |
97 | 97 |
98 // https://w3c.github.io/webappsec/specs/upgrade/ | 98 // https://w3c.github.io/webappsec/specs/upgrade/ |
99 const char ContentSecurityPolicy::UpgradeInsecureRequests[] = "upgrade-insecure-
requests"; | 99 const char ContentSecurityPolicy::UpgradeInsecureRequests[] = "upgrade-insecure-
requests"; |
100 | 100 |
| 101 // Suborigin Directive |
| 102 // https://metromoxie.github.io/webappsec/specs/suborigins/index.html |
| 103 const char ContentSecurityPolicy::Suborigin[] = "suborigin"; |
| 104 |
101 bool ContentSecurityPolicy::isDirectiveName(const String& name) | 105 bool ContentSecurityPolicy::isDirectiveName(const String& name) |
102 { | 106 { |
103 return (equalIgnoringCase(name, ConnectSrc) | 107 return (equalIgnoringCase(name, ConnectSrc) |
104 || equalIgnoringCase(name, DefaultSrc) | 108 || equalIgnoringCase(name, DefaultSrc) |
105 || equalIgnoringCase(name, FontSrc) | 109 || equalIgnoringCase(name, FontSrc) |
106 || equalIgnoringCase(name, FrameSrc) | 110 || equalIgnoringCase(name, FrameSrc) |
107 || equalIgnoringCase(name, ImgSrc) | 111 || equalIgnoringCase(name, ImgSrc) |
108 || equalIgnoringCase(name, MediaSrc) | 112 || equalIgnoringCase(name, MediaSrc) |
109 || equalIgnoringCase(name, ObjectSrc) | 113 || equalIgnoringCase(name, ObjectSrc) |
110 || equalIgnoringCase(name, ReportURI) | 114 || equalIgnoringCase(name, ReportURI) |
111 || equalIgnoringCase(name, Sandbox) | 115 || equalIgnoringCase(name, Sandbox) |
| 116 || equalIgnoringCase(name, Suborigin) |
112 || equalIgnoringCase(name, ScriptSrc) | 117 || equalIgnoringCase(name, ScriptSrc) |
113 || equalIgnoringCase(name, StyleSrc) | 118 || equalIgnoringCase(name, StyleSrc) |
114 || equalIgnoringCase(name, BaseURI) | 119 || equalIgnoringCase(name, BaseURI) |
115 || equalIgnoringCase(name, ChildSrc) | 120 || equalIgnoringCase(name, ChildSrc) |
116 || equalIgnoringCase(name, FormAction) | 121 || equalIgnoringCase(name, FormAction) |
117 || equalIgnoringCase(name, FrameAncestors) | 122 || equalIgnoringCase(name, FrameAncestors) |
118 || equalIgnoringCase(name, PluginTypes) | 123 || equalIgnoringCase(name, PluginTypes) |
119 || equalIgnoringCase(name, ReflectedXSS) | 124 || equalIgnoringCase(name, ReflectedXSS) |
120 || equalIgnoringCase(name, Referrer) | 125 || equalIgnoringCase(name, Referrer) |
121 || equalIgnoringCase(name, ManifestSrc) | 126 || equalIgnoringCase(name, ManifestSrc) |
(...skipping 19 matching lines...) Expand all Loading... |
141 return ReferrerPolicyNever; | 146 return ReferrerPolicyNever; |
142 return a; | 147 return a; |
143 } | 148 } |
144 | 149 |
145 ContentSecurityPolicy::ContentSecurityPolicy() | 150 ContentSecurityPolicy::ContentSecurityPolicy() |
146 : m_executionContext(nullptr) | 151 : m_executionContext(nullptr) |
147 , m_overrideInlineStyleAllowed(false) | 152 , m_overrideInlineStyleAllowed(false) |
148 , m_scriptHashAlgorithmsUsed(ContentSecurityPolicyHashAlgorithmNone) | 153 , m_scriptHashAlgorithmsUsed(ContentSecurityPolicyHashAlgorithmNone) |
149 , m_styleHashAlgorithmsUsed(ContentSecurityPolicyHashAlgorithmNone) | 154 , m_styleHashAlgorithmsUsed(ContentSecurityPolicyHashAlgorithmNone) |
150 , m_sandboxMask(0) | 155 , m_sandboxMask(0) |
| 156 , m_suboriginName(String()) |
151 , m_enforceStrictMixedContentChecking(false) | 157 , m_enforceStrictMixedContentChecking(false) |
152 , m_referrerPolicy(ReferrerPolicyDefault) | 158 , m_referrerPolicy(ReferrerPolicyDefault) |
153 , m_insecureRequestsPolicy(SecurityContext::InsecureRequestsDoNotUpgrade) | 159 , m_insecureRequestsPolicy(SecurityContext::InsecureRequestsDoNotUpgrade) |
154 { | 160 { |
155 } | 161 } |
156 | 162 |
157 void ContentSecurityPolicy::bindToExecutionContext(ExecutionContext* executionCo
ntext) | 163 void ContentSecurityPolicy::bindToExecutionContext(ExecutionContext* executionCo
ntext) |
158 { | 164 { |
159 m_executionContext = executionContext; | 165 m_executionContext = executionContext; |
160 applyPolicySideEffectsToExecutionContext(); | 166 applyPolicySideEffectsToExecutionContext(); |
161 } | 167 } |
162 | 168 |
163 void ContentSecurityPolicy::applyPolicySideEffectsToExecutionContext() | 169 void ContentSecurityPolicy::applyPolicySideEffectsToExecutionContext() |
164 { | 170 { |
165 ASSERT(m_executionContext); | 171 ASSERT(m_executionContext); |
166 ASSERT(securityOrigin()); | 172 ASSERT(securityOrigin()); |
167 // Ensure that 'self' processes correctly. | 173 // Ensure that 'self' processes correctly. |
168 m_selfProtocol = securityOrigin()->protocol(); | 174 m_selfProtocol = securityOrigin()->protocol(); |
169 m_selfSource = adoptPtr(new CSPSource(this, m_selfProtocol, securityOrigin()
->host(), securityOrigin()->port(), String(), CSPSource::NoWildcard, CSPSource::
NoWildcard)); | 175 m_selfSource = adoptPtr(new CSPSource(this, m_selfProtocol, securityOrigin()
->host(), securityOrigin()->port(), String(), CSPSource::NoWildcard, CSPSource::
NoWildcard)); |
170 | 176 |
171 // If we're in a Document, set the referrer policy, mixed content checking,
and sandbox | 177 // If we're in a Document, set the referrer policy, mixed content checking,
and sandbox |
172 // flags, then dump all the parsing error messages, then poke at histograms. | 178 // flags, then dump all the parsing error messages, then poke at histograms. |
173 if (Document* document = this->document()) { | 179 if (Document* document = this->document()) { |
174 if (m_sandboxMask != SandboxNone) { | 180 if (m_sandboxMask != SandboxNone) { |
175 UseCounter::count(document, UseCounter::SandboxViaCSP); | 181 UseCounter::count(document, UseCounter::SandboxViaCSP); |
176 document->enforceSandboxFlags(m_sandboxMask); | 182 document->enforceSandboxFlags(m_sandboxMask); |
177 } | 183 } |
178 if (m_enforceStrictMixedContentChecking) | 184 if (m_enforceStrictMixedContentChecking) |
179 document->enforceStrictMixedContentChecking(); | 185 document->enforceStrictMixedContentChecking(); |
| 186 if (RuntimeEnabledFeatures::suboriginsEnabled()) { |
| 187 document->enforceSuborigin(m_suboriginName); |
| 188 } |
180 if (didSetReferrerPolicy()) | 189 if (didSetReferrerPolicy()) |
181 document->setReferrerPolicy(m_referrerPolicy); | 190 document->setReferrerPolicy(m_referrerPolicy); |
182 if (m_insecureRequestsPolicy == SecurityContext::InsecureRequestsUpgrade
) { | 191 if (m_insecureRequestsPolicy == SecurityContext::InsecureRequestsUpgrade
) { |
183 UseCounter::count(document, UseCounter::UpgradeInsecureRequestsEnabl
ed); | 192 UseCounter::count(document, UseCounter::UpgradeInsecureRequestsEnabl
ed); |
184 document->setInsecureRequestsPolicy(m_insecureRequestsPolicy); | 193 document->setInsecureRequestsPolicy(m_insecureRequestsPolicy); |
185 if (!securityOrigin()->host().isNull()) | 194 if (!securityOrigin()->host().isNull()) |
186 document->addInsecureNavigationUpgrade(securityOrigin()->host().
impl()->hash()); | 195 document->addInsecureNavigationUpgrade(securityOrigin()->host().
impl()->hash()); |
187 } | 196 } |
188 | 197 |
189 for (const auto& consoleMessage : m_consoleMessages) | 198 for (const auto& consoleMessage : m_consoleMessages) |
(...skipping 457 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
647 { | 656 { |
648 m_enforceStrictMixedContentChecking = true; | 657 m_enforceStrictMixedContentChecking = true; |
649 } | 658 } |
650 | 659 |
651 void ContentSecurityPolicy::setInsecureRequestsPolicy(SecurityContext::InsecureR
equestsPolicy policy) | 660 void ContentSecurityPolicy::setInsecureRequestsPolicy(SecurityContext::InsecureR
equestsPolicy policy) |
652 { | 661 { |
653 if (policy > m_insecureRequestsPolicy) | 662 if (policy > m_insecureRequestsPolicy) |
654 m_insecureRequestsPolicy = policy; | 663 m_insecureRequestsPolicy = policy; |
655 } | 664 } |
656 | 665 |
| 666 void ContentSecurityPolicy::enforceSuborigin(const String& name) |
| 667 { |
| 668 m_suboriginName = name; |
| 669 } |
| 670 |
657 static String stripURLForUseInReport(Document* document, const KURL& url) | 671 static String stripURLForUseInReport(Document* document, const KURL& url) |
658 { | 672 { |
659 if (!url.isValid()) | 673 if (!url.isValid()) |
660 return String(); | 674 return String(); |
661 if (!url.isHierarchical() || url.protocolIs("file")) | 675 if (!url.isHierarchical() || url.protocolIs("file")) |
662 return url.protocol(); | 676 return url.protocol(); |
663 return document->securityOrigin()->canRequest(url) ? url.strippedForUseAsRef
errer() : SecurityOrigin::create(url)->toString(); | 677 return document->securityOrigin()->canRequest(url) ? url.strippedForUseAsRef
errer() : SecurityOrigin::create(url)->toString(); |
664 } | 678 } |
665 | 679 |
666 static void gatherSecurityPolicyViolationEventData(SecurityPolicyViolationEventI
nit& init, Document* document, const String& directiveText, const String& effect
iveDirective, const KURL& blockedURL, const String& header) | 680 static void gatherSecurityPolicyViolationEventData(SecurityPolicyViolationEventI
nit& init, Document* document, const String& directiveText, const String& effect
iveDirective, const KURL& blockedURL, const String& header) |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
776 void ContentSecurityPolicy::reportReportOnlyInMeta(const String& header) | 790 void ContentSecurityPolicy::reportReportOnlyInMeta(const String& header) |
777 { | 791 { |
778 logToConsole("The report-only Content Security Policy '" + header + "' was d
elivered via a <meta> element, which is disallowed. The policy has been ignored.
"); | 792 logToConsole("The report-only Content Security Policy '" + header + "' was d
elivered via a <meta> element, which is disallowed. The policy has been ignored.
"); |
779 } | 793 } |
780 | 794 |
781 void ContentSecurityPolicy::reportMetaOutsideHead(const String& header) | 795 void ContentSecurityPolicy::reportMetaOutsideHead(const String& header) |
782 { | 796 { |
783 logToConsole("The Content Security Policy '" + header + "' was delivered via
a <meta> element outside the document's <head>, which is disallowed. The policy
has been ignored."); | 797 logToConsole("The Content Security Policy '" + header + "' was delivered via
a <meta> element outside the document's <head>, which is disallowed. The policy
has been ignored."); |
784 } | 798 } |
785 | 799 |
| 800 void ContentSecurityPolicy::reportSuboriginInMeta(const String& suboriginName) |
| 801 { |
| 802 logToConsole("The Suborigin name '" + suboriginName + "' was delivered via a
Content Security Policy in a <meta> element and not an HTTP header, which is di
sallowed. The Suborigin has been ignored."); |
| 803 } |
| 804 |
786 void ContentSecurityPolicy::reportValueForEmptyDirective(const String& name, con
st String& value) | 805 void ContentSecurityPolicy::reportValueForEmptyDirective(const String& name, con
st String& value) |
787 { | 806 { |
788 logToConsole("The Content Security Policy directive '" + name + "' should be
empty, but was delivered with a value of '" + value + "'. The directive has bee
n applied, and the value ignored."); | 807 logToConsole("The Content Security Policy directive '" + name + "' should be
empty, but was delivered with a value of '" + value + "'. The directive has bee
n applied, and the value ignored."); |
789 } | 808 } |
790 | 809 |
791 void ContentSecurityPolicy::reportInvalidInReportOnly(const String& name) | 810 void ContentSecurityPolicy::reportInvalidInReportOnly(const String& name) |
792 { | 811 { |
793 logToConsole("The Content Security Policy directive '" + name + "' is ignore
d when delivered in a report-only policy."); | 812 logToConsole("The Content Security Policy directive '" + name + "' is ignore
d when delivered in a report-only policy."); |
794 } | 813 } |
795 | 814 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
840 else | 859 else |
841 message = "Invalid plugin type in 'plugin-types' Content Security Policy
directive: '" + pluginType + "'.\n"; | 860 message = "Invalid plugin type in 'plugin-types' Content Security Policy
directive: '" + pluginType + "'.\n"; |
842 logToConsole(message); | 861 logToConsole(message); |
843 } | 862 } |
844 | 863 |
845 void ContentSecurityPolicy::reportInvalidSandboxFlags(const String& invalidFlags
) | 864 void ContentSecurityPolicy::reportInvalidSandboxFlags(const String& invalidFlags
) |
846 { | 865 { |
847 logToConsole("Error while parsing the 'sandbox' Content Security Policy dire
ctive: " + invalidFlags); | 866 logToConsole("Error while parsing the 'sandbox' Content Security Policy dire
ctive: " + invalidFlags); |
848 } | 867 } |
849 | 868 |
| 869 void ContentSecurityPolicy::reportInvalidSuboriginFlags(const String& invalidFla
gs) |
| 870 { |
| 871 logToConsole("Error while parsing the 'suborigin' Content Security Policy di
rective: " + invalidFlags); |
| 872 } |
| 873 |
850 void ContentSecurityPolicy::reportInvalidReflectedXSS(const String& invalidValue
) | 874 void ContentSecurityPolicy::reportInvalidReflectedXSS(const String& invalidValue
) |
851 { | 875 { |
852 logToConsole("The 'reflected-xss' Content Security Policy directive has the
invalid value \"" + invalidValue + "\". Valid values are \"allow\", \"filter\",
and \"block\"."); | 876 logToConsole("The 'reflected-xss' Content Security Policy directive has the
invalid value \"" + invalidValue + "\". Valid values are \"allow\", \"filter\",
and \"block\"."); |
853 } | 877 } |
854 | 878 |
855 void ContentSecurityPolicy::reportInvalidDirectiveValueCharacter(const String& d
irectiveName, const String& value) | 879 void ContentSecurityPolicy::reportInvalidDirectiveValueCharacter(const String& d
irectiveName, const String& value) |
856 { | 880 { |
857 String message = "The value for Content Security Policy directive '" + direc
tiveName + "' contains an invalid character: '" + value + "'. Non-whitespace cha
racters outside ASCII 0x21-0x7E must be percent-encoded, as described in RFC 398
6, section 2.1: http://tools.ietf.org/html/rfc3986#section-2.1."; | 881 String message = "The value for Content Security Policy directive '" + direc
tiveName + "' contains an invalid character: '" + value + "'. Non-whitespace cha
racters outside ASCII 0x21-0x7E must be percent-encoded, as described in RFC 398
6, section 2.1: http://tools.ietf.org/html/rfc3986#section-2.1."; |
858 logToConsole(message); | 882 logToConsole(message); |
859 } | 883 } |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
968 // Collisions have no security impact, so we can save space by storing only
the string's hash rather than the whole report. | 992 // Collisions have no security impact, so we can save space by storing only
the string's hash rather than the whole report. |
969 return !m_violationReportsSent.contains(report.impl()->hash()); | 993 return !m_violationReportsSent.contains(report.impl()->hash()); |
970 } | 994 } |
971 | 995 |
972 void ContentSecurityPolicy::didSendViolationReport(const String& report) | 996 void ContentSecurityPolicy::didSendViolationReport(const String& report) |
973 { | 997 { |
974 m_violationReportsSent.add(report.impl()->hash()); | 998 m_violationReportsSent.add(report.impl()->hash()); |
975 } | 999 } |
976 | 1000 |
977 } // namespace blink | 1001 } // namespace blink |
OLD | NEW |