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