1/*
2 * Copyright (C) 2011 Google, Inc. All rights reserved.
3 * Copyright (C) 2016 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#pragma once
28
29#include "ContentSecurityPolicyHash.h"
30#include "ContentSecurityPolicyResponseHeaders.h"
31#include "SecurityContext.h"
32#include "SecurityOrigin.h"
33#include "SecurityOriginHash.h"
34#include <functional>
35#include <wtf/HashSet.h>
36#include <wtf/Vector.h>
37#include <wtf/text/TextPosition.h>
38
39namespace JSC {
40class ExecState;
41}
42
43namespace WTF {
44class OrdinalNumber;
45}
46
47namespace WebCore {
48
49class ContentSecurityPolicyDirective;
50class ContentSecurityPolicyDirectiveList;
51class ContentSecurityPolicySource;
52class DOMStringList;
53class Frame;
54class JSWindowProxy;
55class ResourceRequest;
56class ScriptExecutionContext;
57class SecurityOrigin;
58class TextEncoding;
59struct ContentSecurityPolicyClient;
60
61typedef Vector<std::unique_ptr<ContentSecurityPolicyDirectiveList>> CSPDirectiveListVector;
62
63class ContentSecurityPolicy {
64 WTF_MAKE_FAST_ALLOCATED;
65public:
66 explicit ContentSecurityPolicy(URL&&, ScriptExecutionContext&);
67 WEBCORE_EXPORT explicit ContentSecurityPolicy(URL&&, ContentSecurityPolicyClient* = nullptr);
68 WEBCORE_EXPORT ~ContentSecurityPolicy();
69
70 void copyStateFrom(const ContentSecurityPolicy*);
71 void copyUpgradeInsecureRequestStateFrom(const ContentSecurityPolicy&);
72 void createPolicyForPluginDocumentFrom(const ContentSecurityPolicy&);
73
74 void didCreateWindowProxy(JSWindowProxy&) const;
75
76 enum class PolicyFrom {
77 API,
78 HTTPEquivMeta,
79 HTTPHeader,
80 Inherited,
81 InheritedForPluginDocument,
82 };
83 WEBCORE_EXPORT ContentSecurityPolicyResponseHeaders responseHeaders() const;
84 enum ReportParsingErrors { No, Yes };
85 WEBCORE_EXPORT void didReceiveHeaders(const ContentSecurityPolicyResponseHeaders&, String&& referrer, ReportParsingErrors = ReportParsingErrors::Yes);
86 void didReceiveHeader(const String&, ContentSecurityPolicyHeaderType, ContentSecurityPolicy::PolicyFrom, String&& referrer, int httpStatusCode = 0);
87
88 bool allowScriptWithNonce(const String& nonce, bool overrideContentSecurityPolicy = false) const;
89 bool allowStyleWithNonce(const String& nonce, bool overrideContentSecurityPolicy = false) const;
90
91 bool allowJavaScriptURLs(const String& contextURL, const WTF::OrdinalNumber& contextLine, bool overrideContentSecurityPolicy = false) const;
92 bool allowInlineEventHandlers(const String& contextURL, const WTF::OrdinalNumber& contextLine, bool overrideContentSecurityPolicy = false) const;
93 bool allowInlineScript(const String& contextURL, const WTF::OrdinalNumber& contextLine, const String& scriptContent, bool overrideContentSecurityPolicy = false) const;
94 bool allowInlineStyle(const String& contextURL, const WTF::OrdinalNumber& contextLine, const String& styleContent, bool overrideContentSecurityPolicy = false) const;
95
96 bool allowEval(JSC::ExecState*, bool overrideContentSecurityPolicy = false) const;
97
98 bool allowPluginType(const String& type, const String& typeAttribute, const URL&, bool overrideContentSecurityPolicy = false) const;
99
100 bool allowFrameAncestors(const Frame&, const URL&, bool overrideContentSecurityPolicy = false) const;
101 WEBCORE_EXPORT bool allowFrameAncestors(const Vector<RefPtr<SecurityOrigin>>& ancestorOrigins, const URL&, bool overrideContentSecurityPolicy = false) const;
102 WEBCORE_EXPORT bool overridesXFrameOptions() const;
103
104 enum class RedirectResponseReceived { No, Yes };
105 WEBCORE_EXPORT bool allowScriptFromSource(const URL&, RedirectResponseReceived = RedirectResponseReceived::No) const;
106 bool allowImageFromSource(const URL&, RedirectResponseReceived = RedirectResponseReceived::No) const;
107 bool allowStyleFromSource(const URL&, RedirectResponseReceived = RedirectResponseReceived::No) const;
108 bool allowFontFromSource(const URL&, RedirectResponseReceived = RedirectResponseReceived::No) const;
109#if ENABLE(APPLICATION_MANIFEST)
110 bool allowManifestFromSource(const URL&, RedirectResponseReceived = RedirectResponseReceived::No) const;
111#endif
112 bool allowMediaFromSource(const URL&, RedirectResponseReceived = RedirectResponseReceived::No) const;
113
114 bool allowChildFrameFromSource(const URL&, RedirectResponseReceived = RedirectResponseReceived::No) const;
115 WEBCORE_EXPORT bool allowChildContextFromSource(const URL&, RedirectResponseReceived = RedirectResponseReceived::No) const;
116 WEBCORE_EXPORT bool allowConnectToSource(const URL&, RedirectResponseReceived = RedirectResponseReceived::No) const;
117 bool allowFormAction(const URL&, RedirectResponseReceived = RedirectResponseReceived::No) const;
118
119 bool allowObjectFromSource(const URL&, RedirectResponseReceived = RedirectResponseReceived::No) const;
120 bool allowBaseURI(const URL&, bool overrideContentSecurityPolicy = false) const;
121
122 void setOverrideAllowInlineStyle(bool);
123
124 void gatherReportURIs(DOMStringList&) const;
125
126 bool allowRunningOrDisplayingInsecureContent(const URL&);
127
128 // The following functions are used by internal data structures to call back into this object when parsing, validating,
129 // and applying a Content Security Policy.
130 // FIXME: We should make the various directives serve only as state stores for the parsed policy and remove these functions.
131 // This class should traverse the directives, validating the policy, and applying it to the script execution context.
132
133 // Used by ContentSecurityPolicyMediaListDirective
134 void reportInvalidPluginTypes(const String&) const;
135
136 // Used by ContentSecurityPolicySourceList
137 void reportDirectiveAsSourceExpression(const String& directiveName, const String& sourceExpression) const;
138 void reportInvalidPathCharacter(const String& directiveName, const String& value, const char) const;
139 void reportInvalidSourceExpression(const String& directiveName, const String& source) const;
140 bool urlMatchesSelf(const URL&) const;
141 bool allowContentSecurityPolicySourceStarToMatchAnyProtocol() const;
142
143 // Used by ContentSecurityPolicyDirectiveList
144 void reportDuplicateDirective(const String&) const;
145 void reportInvalidDirectiveValueCharacter(const String& directiveName, const String& value) const;
146 void reportInvalidSandboxFlags(const String&) const;
147 void reportInvalidDirectiveInReportOnlyMode(const String&) const;
148 void reportInvalidDirectiveInHTTPEquivMeta(const String&) const;
149 void reportMissingReportURI(const String&) const;
150 void reportUnsupportedDirective(const String&) const;
151 void enforceSandboxFlags(SandboxFlags sandboxFlags) { m_sandboxFlags |= sandboxFlags; }
152 void addHashAlgorithmsForInlineScripts(OptionSet<ContentSecurityPolicyHashAlgorithm> hashAlgorithmsForInlineScripts)
153 {
154 m_hashAlgorithmsForInlineScripts.add(hashAlgorithmsForInlineScripts);
155 }
156 void addHashAlgorithmsForInlineStylesheets(OptionSet<ContentSecurityPolicyHashAlgorithm> hashAlgorithmsForInlineStylesheets)
157 {
158 m_hashAlgorithmsForInlineStylesheets.add(hashAlgorithmsForInlineStylesheets);
159 }
160
161 // Used by ContentSecurityPolicySource
162 bool protocolMatchesSelf(const URL&) const;
163
164 void setUpgradeInsecureRequests(bool);
165 bool upgradeInsecureRequests() const { return m_upgradeInsecureRequests; }
166 enum class InsecureRequestType { Load, FormSubmission, Navigation };
167 WEBCORE_EXPORT void upgradeInsecureRequestIfNeeded(ResourceRequest&, InsecureRequestType) const;
168 WEBCORE_EXPORT void upgradeInsecureRequestIfNeeded(URL&, InsecureRequestType) const;
169
170 HashSet<SecurityOriginData> takeNavigationRequestsToUpgrade();
171 void inheritInsecureNavigationRequestsToUpgradeFromOpener(const ContentSecurityPolicy&);
172 void setInsecureNavigationRequestsToUpgrade(HashSet<SecurityOriginData>&&);
173
174 void setClient(ContentSecurityPolicyClient* client) { m_client = client; }
175
176private:
177 void logToConsole(const String& message, const String& contextURL = String(), const WTF::OrdinalNumber& contextLine = WTF::OrdinalNumber::beforeFirst(), const WTF::OrdinalNumber& contextColumn = WTF::OrdinalNumber::beforeFirst(), JSC::ExecState* = nullptr) const;
178 void updateSourceSelf(const SecurityOrigin&);
179 void applyPolicyToScriptExecutionContext();
180
181 // Implements the deprecated CSP2 "strip uri for reporting" algorithm from <https://www.w3.org/TR/CSP2/#violation-reports>.
182 String deprecatedURLForReporting(const URL&) const;
183
184 const TextEncoding& documentEncoding() const;
185
186 enum class Disposition {
187 Enforce,
188 ReportOnly,
189 };
190
191 using ViolatedDirectiveCallback = std::function<void (const ContentSecurityPolicyDirective&)>;
192
193 template<typename Predicate, typename... Args>
194 typename std::enable_if<!std::is_convertible<Predicate, ViolatedDirectiveCallback>::value, bool>::type allPoliciesWithDispositionAllow(Disposition, Predicate&&, Args&&...) const;
195
196 template<typename Predicate, typename... Args>
197 bool allPoliciesWithDispositionAllow(Disposition, ViolatedDirectiveCallback&&, Predicate&&, Args&&...) const;
198
199 template<typename Predicate, typename... Args>
200 bool allPoliciesAllow(ViolatedDirectiveCallback&&, Predicate&&, Args&&...) const WARN_UNUSED_RETURN;
201
202 using ResourcePredicate = const ContentSecurityPolicyDirective *(ContentSecurityPolicyDirectiveList::*)(const URL &, bool) const;
203 bool allowResourceFromSource(const URL&, RedirectResponseReceived, const char*, ResourcePredicate) const;
204
205 using HashInEnforcedAndReportOnlyPoliciesPair = std::pair<bool, bool>;
206 template<typename Predicate> HashInEnforcedAndReportOnlyPoliciesPair findHashOfContentInPolicies(Predicate&&, const String& content, OptionSet<ContentSecurityPolicyHashAlgorithm>) const WARN_UNUSED_RETURN;
207
208 void reportViolation(const String& effectiveViolatedDirective, const ContentSecurityPolicyDirective& violatedDirective, const URL& blockedURL, const String& consoleMessage, JSC::ExecState*) const;
209 void reportViolation(const String& effectiveViolatedDirective, const String& violatedDirective, const ContentSecurityPolicyDirectiveList&, const URL& blockedURL, const String& consoleMessage, JSC::ExecState* = nullptr) const;
210 void reportViolation(const String& effectiveViolatedDirective, const ContentSecurityPolicyDirective& violatedDirective, const URL& blockedURL, const String& consoleMessage, const String& sourceURL, const TextPosition& sourcePosition, JSC::ExecState* = nullptr) const;
211 void reportViolation(const String& effectiveViolatedDirective, const String& violatedDirective, const ContentSecurityPolicyDirectiveList& violatedDirectiveList, const URL& blockedURL, const String& consoleMessage, const String& sourceURL, const TextPosition& sourcePosition, JSC::ExecState*) const;
212 void reportBlockedScriptExecutionToInspector(const String& directiveText) const;
213
214 // We can never have both a script execution context and a ContentSecurityPolicyClient.
215 ScriptExecutionContext* m_scriptExecutionContext { nullptr };
216 ContentSecurityPolicyClient* m_client { nullptr };
217 URL m_protectedURL;
218 std::unique_ptr<ContentSecurityPolicySource> m_selfSource;
219 String m_selfSourceProtocol;
220 CSPDirectiveListVector m_policies;
221 String m_lastPolicyEvalDisabledErrorMessage;
222 String m_lastPolicyWebAssemblyDisabledErrorMessage;
223 String m_referrer;
224 SandboxFlags m_sandboxFlags { SandboxNone };
225 bool m_overrideInlineStyleAllowed { false };
226 bool m_isReportingEnabled { true };
227 bool m_upgradeInsecureRequests { false };
228 bool m_hasAPIPolicy { false };
229 int m_httpStatusCode { 0 };
230 OptionSet<ContentSecurityPolicyHashAlgorithm> m_hashAlgorithmsForInlineScripts;
231 OptionSet<ContentSecurityPolicyHashAlgorithm> m_hashAlgorithmsForInlineStylesheets;
232 HashSet<SecurityOriginData> m_insecureNavigationRequestsToUpgrade;
233 mutable Optional<ContentSecurityPolicyResponseHeaders> m_cachedResponseHeaders;
234};
235
236}
237