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 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 // https://w3c.github.io/manifest/#content-security-policy | 89 // https://w3c.github.io/manifest/#content-security-policy |
90 const char ContentSecurityPolicy::ManifestSrc[] = "manifest-src"; | 90 const char ContentSecurityPolicy::ManifestSrc[] = "manifest-src"; |
91 | 91 |
92 // Mixed Content Directive | 92 // Mixed Content Directive |
93 // https://w3c.github.io/webappsec/specs/mixedcontent/#strict-mode | 93 // https://w3c.github.io/webappsec/specs/mixedcontent/#strict-mode |
94 const char ContentSecurityPolicy::BlockAllMixedContent[] = "block-all-mixed-cont
ent"; | 94 const char ContentSecurityPolicy::BlockAllMixedContent[] = "block-all-mixed-cont
ent"; |
95 | 95 |
96 // https://w3c.github.io/webappsec/specs/upgrade/ | 96 // https://w3c.github.io/webappsec/specs/upgrade/ |
97 const char ContentSecurityPolicy::UpgradeInsecureRequests[] = "upgrade-insecure-
requests"; | 97 const char ContentSecurityPolicy::UpgradeInsecureRequests[] = "upgrade-insecure-
requests"; |
98 | 98 |
| 99 // Suborigin Directive |
| 100 // https://metromoxie.github.io/webappsec/specs/suborigins/index.html |
| 101 const char ContentSecurityPolicy::Suborigin[] = "suborigin"; |
| 102 |
99 bool ContentSecurityPolicy::isDirectiveName(const String& name) | 103 bool ContentSecurityPolicy::isDirectiveName(const String& name) |
100 { | 104 { |
101 return (equalIgnoringCase(name, ConnectSrc) | 105 return (equalIgnoringCase(name, ConnectSrc) |
102 || equalIgnoringCase(name, DefaultSrc) | 106 || equalIgnoringCase(name, DefaultSrc) |
103 || equalIgnoringCase(name, FontSrc) | 107 || equalIgnoringCase(name, FontSrc) |
104 || equalIgnoringCase(name, FrameSrc) | 108 || equalIgnoringCase(name, FrameSrc) |
105 || equalIgnoringCase(name, ImgSrc) | 109 || equalIgnoringCase(name, ImgSrc) |
106 || equalIgnoringCase(name, MediaSrc) | 110 || equalIgnoringCase(name, MediaSrc) |
107 || equalIgnoringCase(name, ObjectSrc) | 111 || equalIgnoringCase(name, ObjectSrc) |
108 || equalIgnoringCase(name, ReportURI) | 112 || equalIgnoringCase(name, ReportURI) |
109 || equalIgnoringCase(name, Sandbox) | 113 || equalIgnoringCase(name, Sandbox) |
| 114 || equalIgnoringCase(name, Suborigin) |
110 || equalIgnoringCase(name, ScriptSrc) | 115 || equalIgnoringCase(name, ScriptSrc) |
111 || equalIgnoringCase(name, StyleSrc) | 116 || equalIgnoringCase(name, StyleSrc) |
112 || equalIgnoringCase(name, BaseURI) | 117 || equalIgnoringCase(name, BaseURI) |
113 || equalIgnoringCase(name, ChildSrc) | 118 || equalIgnoringCase(name, ChildSrc) |
114 || equalIgnoringCase(name, FormAction) | 119 || equalIgnoringCase(name, FormAction) |
115 || equalIgnoringCase(name, FrameAncestors) | 120 || equalIgnoringCase(name, FrameAncestors) |
116 || equalIgnoringCase(name, PluginTypes) | 121 || equalIgnoringCase(name, PluginTypes) |
117 || equalIgnoringCase(name, ReflectedXSS) | 122 || equalIgnoringCase(name, ReflectedXSS) |
118 || equalIgnoringCase(name, Referrer) | 123 || equalIgnoringCase(name, Referrer) |
119 || equalIgnoringCase(name, ManifestSrc) | 124 || equalIgnoringCase(name, ManifestSrc) |
(...skipping 19 matching lines...) Expand all Loading... |
139 return ReferrerPolicyNever; | 144 return ReferrerPolicyNever; |
140 return a; | 145 return a; |
141 } | 146 } |
142 | 147 |
143 ContentSecurityPolicy::ContentSecurityPolicy() | 148 ContentSecurityPolicy::ContentSecurityPolicy() |
144 : m_executionContext(nullptr) | 149 : m_executionContext(nullptr) |
145 , m_overrideInlineStyleAllowed(false) | 150 , m_overrideInlineStyleAllowed(false) |
146 , m_scriptHashAlgorithmsUsed(ContentSecurityPolicyHashAlgorithmNone) | 151 , m_scriptHashAlgorithmsUsed(ContentSecurityPolicyHashAlgorithmNone) |
147 , m_styleHashAlgorithmsUsed(ContentSecurityPolicyHashAlgorithmNone) | 152 , m_styleHashAlgorithmsUsed(ContentSecurityPolicyHashAlgorithmNone) |
148 , m_sandboxMask(0) | 153 , m_sandboxMask(0) |
| 154 , m_suboriginName(String()) |
149 , m_enforceStrictMixedContentChecking(false) | 155 , m_enforceStrictMixedContentChecking(false) |
150 , m_referrerPolicy(ReferrerPolicyDefault) | 156 , m_referrerPolicy(ReferrerPolicyDefault) |
151 , m_insecureRequestsPolicy(SecurityContext::InsecureRequestsDoNotUpgrade) | 157 , m_insecureRequestsPolicy(SecurityContext::InsecureRequestsDoNotUpgrade) |
152 { | 158 { |
153 } | 159 } |
154 | 160 |
155 void ContentSecurityPolicy::bindToExecutionContext(ExecutionContext* executionCo
ntext) | 161 void ContentSecurityPolicy::bindToExecutionContext(ExecutionContext* executionCo
ntext) |
156 { | 162 { |
157 m_executionContext = executionContext; | 163 m_executionContext = executionContext; |
158 applyPolicySideEffectsToExecutionContext(); | 164 applyPolicySideEffectsToExecutionContext(); |
159 } | 165 } |
160 | 166 |
161 void ContentSecurityPolicy::applyPolicySideEffectsToExecutionContext() | 167 void ContentSecurityPolicy::applyPolicySideEffectsToExecutionContext() |
162 { | 168 { |
163 ASSERT(m_executionContext); | 169 ASSERT(m_executionContext); |
164 // Ensure that 'self' processes correctly. | 170 // Ensure that 'self' processes correctly. |
165 m_selfProtocol = securityOrigin()->protocol(); | 171 m_selfProtocol = securityOrigin()->protocol(); |
166 m_selfSource = adoptPtr(new CSPSource(this, m_selfProtocol, securityOrigin()
->host(), securityOrigin()->port(), String(), CSPSource::NoWildcard, CSPSource::
NoWildcard)); | 172 m_selfSource = adoptPtr(new CSPSource(this, m_selfProtocol, securityOrigin()
->host(), securityOrigin()->port(), String(), CSPSource::NoWildcard, CSPSource::
NoWildcard)); |
167 | 173 |
168 // If we're in a Document, set the referrer policy, mixed content checking,
and sandbox | 174 // If we're in a Document, set the referrer policy, mixed content checking,
and sandbox |
169 // flags, then dump all the parsing error messages, then poke at histograms. | 175 // flags, then dump all the parsing error messages, then poke at histograms. |
170 if (Document* document = this->document()) { | 176 if (Document* document = this->document()) { |
171 if (m_sandboxMask != SandboxNone) { | 177 if (m_sandboxMask != SandboxNone) { |
172 UseCounter::count(document, UseCounter::SandboxViaCSP); | 178 UseCounter::count(document, UseCounter::SandboxViaCSP); |
173 document->enforceSandboxFlags(m_sandboxMask); | 179 document->enforceSandboxFlags(m_sandboxMask); |
174 } | 180 } |
175 if (m_enforceStrictMixedContentChecking) | 181 if (m_enforceStrictMixedContentChecking) |
176 document->enforceStrictMixedContentChecking(); | 182 document->enforceStrictMixedContentChecking(); |
| 183 if (RuntimeEnabledFeatures::suboriginsEnabled()) { |
| 184 document->enforceSuborigin(m_suboriginName); |
| 185 } |
177 if (didSetReferrerPolicy()) | 186 if (didSetReferrerPolicy()) |
178 document->setReferrerPolicy(m_referrerPolicy); | 187 document->setReferrerPolicy(m_referrerPolicy); |
179 if (m_insecureRequestsPolicy > document->insecureRequestsPolicy()) | 188 if (m_insecureRequestsPolicy > document->insecureRequestsPolicy()) |
180 document->setInsecureRequestsPolicy(m_insecureRequestsPolicy); | 189 document->setInsecureRequestsPolicy(m_insecureRequestsPolicy); |
181 | 190 |
182 for (const auto& consoleMessage : m_consoleMessages) | 191 for (const auto& consoleMessage : m_consoleMessages) |
183 m_executionContext->addConsoleMessage(consoleMessage); | 192 m_executionContext->addConsoleMessage(consoleMessage); |
184 m_consoleMessages.clear(); | 193 m_consoleMessages.clear(); |
185 | 194 |
186 for (const auto& policy : m_policies) | 195 for (const auto& policy : m_policies) |
(...skipping 453 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
640 { | 649 { |
641 m_enforceStrictMixedContentChecking = true; | 650 m_enforceStrictMixedContentChecking = true; |
642 } | 651 } |
643 | 652 |
644 void ContentSecurityPolicy::setInsecureRequestsPolicy(SecurityContext::InsecureR
equestsPolicy policy) | 653 void ContentSecurityPolicy::setInsecureRequestsPolicy(SecurityContext::InsecureR
equestsPolicy policy) |
645 { | 654 { |
646 if (policy > m_insecureRequestsPolicy) | 655 if (policy > m_insecureRequestsPolicy) |
647 m_insecureRequestsPolicy = policy; | 656 m_insecureRequestsPolicy = policy; |
648 } | 657 } |
649 | 658 |
| 659 void ContentSecurityPolicy::enforceSuborigin(const String& name) |
| 660 { |
| 661 m_suboriginName = name; |
| 662 } |
| 663 |
650 static String stripURLForUseInReport(Document* document, const KURL& url) | 664 static String stripURLForUseInReport(Document* document, const KURL& url) |
651 { | 665 { |
652 if (!url.isValid()) | 666 if (!url.isValid()) |
653 return String(); | 667 return String(); |
654 if (!url.isHierarchical() || url.protocolIs("file")) | 668 if (!url.isHierarchical() || url.protocolIs("file")) |
655 return url.protocol(); | 669 return url.protocol(); |
656 return document->securityOrigin()->canRequest(url) ? url.strippedForUseAsRef
errer() : SecurityOrigin::create(url)->toString(); | 670 return document->securityOrigin()->canRequest(url) ? url.strippedForUseAsRef
errer() : SecurityOrigin::create(url)->toString(); |
657 } | 671 } |
658 | 672 |
659 static void gatherSecurityPolicyViolationEventData(SecurityPolicyViolationEventI
nit& init, Document* document, const String& directiveText, const String& effect
iveDirective, const KURL& blockedURL, const String& header) | 673 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... |
769 void ContentSecurityPolicy::reportReportOnlyInMeta(const String& header) | 783 void ContentSecurityPolicy::reportReportOnlyInMeta(const String& header) |
770 { | 784 { |
771 logToConsole("The report-only Content Security Policy '" + header + "' was d
elivered via a <meta> element, which is disallowed. The policy has been ignored.
"); | 785 logToConsole("The report-only Content Security Policy '" + header + "' was d
elivered via a <meta> element, which is disallowed. The policy has been ignored.
"); |
772 } | 786 } |
773 | 787 |
774 void ContentSecurityPolicy::reportMetaOutsideHead(const String& header) | 788 void ContentSecurityPolicy::reportMetaOutsideHead(const String& header) |
775 { | 789 { |
776 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."); | 790 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."); |
777 } | 791 } |
778 | 792 |
| 793 void ContentSecurityPolicy::reportSuboriginInMeta(const String& suboriginName) |
| 794 { |
| 795 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."); |
| 796 } |
| 797 |
779 void ContentSecurityPolicy::reportValueForEmptyDirective(const String& name, con
st String& value) | 798 void ContentSecurityPolicy::reportValueForEmptyDirective(const String& name, con
st String& value) |
780 { | 799 { |
781 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."); | 800 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."); |
782 } | 801 } |
783 | 802 |
784 void ContentSecurityPolicy::reportInvalidInReportOnly(const String& name) | 803 void ContentSecurityPolicy::reportInvalidInReportOnly(const String& name) |
785 { | 804 { |
786 logToConsole("The Content Security Policy directive '" + name + "' is ignore
d when delivered in a report-only policy."); | 805 logToConsole("The Content Security Policy directive '" + name + "' is ignore
d when delivered in a report-only policy."); |
787 } | 806 } |
788 | 807 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
833 else | 852 else |
834 message = "Invalid plugin type in 'plugin-types' Content Security Policy
directive: '" + pluginType + "'.\n"; | 853 message = "Invalid plugin type in 'plugin-types' Content Security Policy
directive: '" + pluginType + "'.\n"; |
835 logToConsole(message); | 854 logToConsole(message); |
836 } | 855 } |
837 | 856 |
838 void ContentSecurityPolicy::reportInvalidSandboxFlags(const String& invalidFlags
) | 857 void ContentSecurityPolicy::reportInvalidSandboxFlags(const String& invalidFlags
) |
839 { | 858 { |
840 logToConsole("Error while parsing the 'sandbox' Content Security Policy dire
ctive: " + invalidFlags); | 859 logToConsole("Error while parsing the 'sandbox' Content Security Policy dire
ctive: " + invalidFlags); |
841 } | 860 } |
842 | 861 |
| 862 void ContentSecurityPolicy::reportInvalidSuboriginFlags(const String& invalidFla
gs) |
| 863 { |
| 864 logToConsole("Error while parsing the 'suborigin' Content Security Policy di
rective: " + invalidFlags); |
| 865 } |
| 866 |
843 void ContentSecurityPolicy::reportInvalidReflectedXSS(const String& invalidValue
) | 867 void ContentSecurityPolicy::reportInvalidReflectedXSS(const String& invalidValue
) |
844 { | 868 { |
845 logToConsole("The 'reflected-xss' Content Security Policy directive has the
invalid value \"" + invalidValue + "\". Valid values are \"allow\", \"filter\",
and \"block\"."); | 869 logToConsole("The 'reflected-xss' Content Security Policy directive has the
invalid value \"" + invalidValue + "\". Valid values are \"allow\", \"filter\",
and \"block\"."); |
846 } | 870 } |
847 | 871 |
848 void ContentSecurityPolicy::reportInvalidDirectiveValueCharacter(const String& d
irectiveName, const String& value) | 872 void ContentSecurityPolicy::reportInvalidDirectiveValueCharacter(const String& d
irectiveName, const String& value) |
849 { | 873 { |
850 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."; | 874 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."; |
851 logToConsole(message); | 875 logToConsole(message); |
852 } | 876 } |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
927 // Collisions have no security impact, so we can save space by storing only
the string's hash rather than the whole report. | 951 // Collisions have no security impact, so we can save space by storing only
the string's hash rather than the whole report. |
928 return !m_violationReportsSent.contains(report.impl()->hash()); | 952 return !m_violationReportsSent.contains(report.impl()->hash()); |
929 } | 953 } |
930 | 954 |
931 void ContentSecurityPolicy::didSendViolationReport(const String& report) | 955 void ContentSecurityPolicy::didSendViolationReport(const String& report) |
932 { | 956 { |
933 m_violationReportsSent.add(report.impl()->hash()); | 957 m_violationReportsSent.add(report.impl()->hash()); |
934 } | 958 } |
935 | 959 |
936 } // namespace blink | 960 } // namespace blink |
OLD | NEW |