1 | /* |
2 | * Copyright (C) 2007-2018 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * |
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 | * 3. Neither the name of Apple Inc. ("Apple") nor the names of |
14 | * its contributors may be used to endorse or promote products derived |
15 | * from this software without specific prior written permission. |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
18 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
20 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
28 | |
29 | #pragma once |
30 | |
31 | #include "SecurityOriginData.h" |
32 | #include <wtf/ThreadSafeRefCounted.h> |
33 | #include <wtf/text/WTFString.h> |
34 | |
35 | namespace WebCore { |
36 | |
37 | class SecurityOrigin : public ThreadSafeRefCounted<SecurityOrigin> { |
38 | public: |
39 | enum Policy { |
40 | AlwaysDeny = 0, |
41 | AlwaysAllow, |
42 | Ask |
43 | }; |
44 | |
45 | enum StorageBlockingPolicy { |
46 | AllowAllStorage = 0, |
47 | BlockThirdPartyStorage, |
48 | BlockAllStorage |
49 | }; |
50 | |
51 | WEBCORE_EXPORT static Ref<SecurityOrigin> create(const URL&); |
52 | WEBCORE_EXPORT static Ref<SecurityOrigin> createUnique(); |
53 | |
54 | WEBCORE_EXPORT static Ref<SecurityOrigin> createFromString(const String&); |
55 | WEBCORE_EXPORT static Ref<SecurityOrigin> create(const String& protocol, const String& host, Optional<uint16_t> port); |
56 | |
57 | // QuickLook documents are in non-local origins even when loaded from file: URLs. They need to |
58 | // be allowed to display their own file: URLs in order to perform reloads and same-document |
59 | // navigations. This lets those documents specify the file path that should be allowed to be |
60 | // displayed from their non-local origin. |
61 | static Ref<SecurityOrigin> createNonLocalWithAllowedFilePath(const URL&, const String& filePath); |
62 | |
63 | // Some URL schemes use nested URLs for their security context. For example, |
64 | // filesystem URLs look like the following: |
65 | // |
66 | // filesystem:http://example.com/temporary/path/to/file.png |
67 | // |
68 | // We're supposed to use "http://example.com" as the origin. |
69 | // |
70 | // Generally, we add URL schemes to this list when WebKit support them. For |
71 | // example, we don't include the "jar" scheme, even though Firefox |
72 | // understands that "jar" uses an inner URL for it's security origin. |
73 | static bool shouldUseInnerURL(const URL&); |
74 | static URL (const URL&); |
75 | |
76 | // Create a deep copy of this SecurityOrigin. This method is useful |
77 | // when marshalling a SecurityOrigin to another thread. |
78 | WEBCORE_EXPORT Ref<SecurityOrigin> isolatedCopy() const; |
79 | |
80 | // Set the domain property of this security origin to newDomain. This |
81 | // function does not check whether newDomain is a suffix of the current |
82 | // domain. The caller is responsible for validating newDomain. |
83 | void setDomainFromDOM(const String& newDomain); |
84 | bool domainWasSetInDOM() const { return m_domainWasSetInDOM; } |
85 | |
86 | const String& protocol() const { return m_data.protocol; } |
87 | const String& host() const { return m_data.host; } |
88 | const String& domain() const { return m_domain; } |
89 | Optional<uint16_t> port() const { return m_data.port; } |
90 | |
91 | // Returns true if a given URL is secure, based either directly on its |
92 | // own protocol, or, when relevant, on the protocol of its "inner URL" |
93 | // Protocols like blob: and filesystem: fall into this latter category. |
94 | static bool isSecure(const URL&); |
95 | |
96 | // Returns true if this SecurityOrigin can script objects in the given |
97 | // SecurityOrigin. For example, call this function before allowing |
98 | // script from one security origin to read or write objects from |
99 | // another SecurityOrigin. |
100 | WEBCORE_EXPORT bool canAccess(const SecurityOrigin&) const; |
101 | |
102 | // Returns true if this SecurityOrigin can read content retrieved from |
103 | // the given URL. For example, call this function before issuing |
104 | // XMLHttpRequests. |
105 | WEBCORE_EXPORT bool canRequest(const URL&) const; |
106 | |
107 | // Returns true if this SecurityOrigin can receive drag content from the |
108 | // initiator. For example, call this function before allowing content to be |
109 | // dropped onto a target. |
110 | bool canReceiveDragData(const SecurityOrigin& dragInitiator) const; |
111 | |
112 | // Returns true if |document| can display content from the given URL (e.g., |
113 | // in an iframe or as an image). For example, web sites generally cannot |
114 | // display content from the user's files system. |
115 | WEBCORE_EXPORT bool canDisplay(const URL&) const; |
116 | |
117 | // Returns true if this SecurityOrigin can load local resources, such |
118 | // as images, iframes, and style sheets, and can link to local URLs. |
119 | // For example, call this function before creating an iframe to a |
120 | // file:// URL. |
121 | // |
122 | // Note: A SecurityOrigin might be allowed to load local resources |
123 | // without being able to issue an XMLHttpRequest for a local URL. |
124 | // To determine whether the SecurityOrigin can issue an |
125 | // XMLHttpRequest for a URL, call canRequest(url). |
126 | bool canLoadLocalResources() const { return m_canLoadLocalResources; } |
127 | |
128 | // Explicitly grant the ability to load local resources to this |
129 | // SecurityOrigin. |
130 | // |
131 | // Note: This method exists only to support backwards compatibility |
132 | // with older versions of WebKit. |
133 | void grantLoadLocalResources(); |
134 | |
135 | // Explicitly grant the ability to access very other SecurityOrigin. |
136 | // |
137 | // WARNING: This is an extremely powerful ability. Use with caution! |
138 | void grantUniversalAccess(); |
139 | bool hasUniversalAccess() const { return m_universalAccess; } |
140 | |
141 | void setStorageBlockingPolicy(StorageBlockingPolicy policy) { m_storageBlockingPolicy = policy; } |
142 | |
143 | void grantStorageAccessFromFileURLsQuirk(); |
144 | bool needsStorageAccessFromFileURLsQuirk() const { return m_needsStorageAccessFromFileURLsQuirk; } |
145 | |
146 | WEBCORE_EXPORT String domainForCachePartition() const; |
147 | |
148 | bool canAccessDatabase(const SecurityOrigin& topOrigin) const { return canAccessStorage(&topOrigin); }; |
149 | bool canAccessSessionStorage(const SecurityOrigin& topOrigin) const { return canAccessStorage(&topOrigin, AlwaysAllowFromThirdParty); } |
150 | bool canAccessLocalStorage(const SecurityOrigin* topOrigin) const { return canAccessStorage(topOrigin); }; |
151 | bool canAccessPluginStorage(const SecurityOrigin& topOrigin) const { return canAccessStorage(&topOrigin); } |
152 | bool canAccessApplicationCache(const SecurityOrigin& topOrigin) const { return canAccessStorage(&topOrigin); } |
153 | bool canAccessCookies() const { return !isUnique(); } |
154 | bool canRequestGeolocation() const { return !isUnique(); } |
155 | Policy canShowNotifications() const; |
156 | |
157 | // The local SecurityOrigin is the most privileged SecurityOrigin. |
158 | // The local SecurityOrigin can script any document, navigate to local |
159 | // resources, and can set arbitrary headers on XMLHttpRequests. |
160 | bool isLocal() const { return m_isLocal; } |
161 | |
162 | // The origin is a globally unique identifier assigned when the Document is |
163 | // created. http://www.whatwg.org/specs/web-apps/current-work/#sandboxOrigin |
164 | // |
165 | // There's a subtle difference between a unique origin and an origin that |
166 | // has the SandboxOrigin flag set. The latter implies the former, and, in |
167 | // addition, the SandboxOrigin flag is inherited by iframes. |
168 | bool isUnique() const { return m_isUnique; } |
169 | |
170 | // Marks a file:// origin as being in a domain defined by its path. |
171 | // FIXME 81578: The naming of this is confusing. Files with restricted access to other local files |
172 | // still can have other privileges that can be remembered, thereby not making them unique. |
173 | void setEnforcesFilePathSeparation(); |
174 | bool enforcesFilePathSeparation() const { return m_enforcesFilePathSeparation; } |
175 | |
176 | // Convert this SecurityOrigin into a string. The string |
177 | // representation of a SecurityOrigin is similar to a URL, except it |
178 | // lacks a path component. The string representation does not encode |
179 | // the value of the SecurityOrigin's domain property. |
180 | // |
181 | // When using the string value, it's important to remember that it might be |
182 | // "null". This happens when this SecurityOrigin is unique. For example, |
183 | // this SecurityOrigin might have come from a sandboxed iframe, the |
184 | // SecurityOrigin might be empty, or we might have explicitly decided that |
185 | // we shouldTreatURLSchemeAsNoAccess. |
186 | WEBCORE_EXPORT String toString() const; |
187 | |
188 | // Similar to toString(), but does not take into account any factors that |
189 | // could make the string return "null". |
190 | WEBCORE_EXPORT String toRawString() const; |
191 | |
192 | // This method checks for equality between SecurityOrigins, not whether |
193 | // one origin can access another. It is used for hash table keys. |
194 | // For access checks, use canAccess(). |
195 | // FIXME: If this method is really only useful for hash table keys, it |
196 | // should be refactored into SecurityOriginHash. |
197 | WEBCORE_EXPORT bool equal(const SecurityOrigin*) const; |
198 | |
199 | // This method checks for equality, ignoring the value of document.domain |
200 | // (and whether it was set) but considering the host. It is used for postMessage. |
201 | WEBCORE_EXPORT bool isSameSchemeHostPort(const SecurityOrigin&) const; |
202 | |
203 | // This method implements the "same origin" algorithm from the HTML Standard: |
204 | // https://html.spec.whatwg.org/multipage/browsers.html#same-origin |
205 | WEBCORE_EXPORT bool isSameOriginAs(const SecurityOrigin&) const; |
206 | |
207 | // This method implements the "is a registrable domain suffix of or is equal to" algorithm from the HTML Standard: |
208 | // https://html.spec.whatwg.org/multipage/origin.html#is-a-registrable-domain-suffix-of-or-is-equal-to |
209 | WEBCORE_EXPORT bool isMatchingRegistrableDomainSuffix(const String&, bool treatIPAddressAsDomain = false) const; |
210 | |
211 | bool isPotentiallyTrustworthy() const { return m_isPotentiallyTrustworthy; } |
212 | void setIsPotentiallyTrustworthy(bool value) { m_isPotentiallyTrustworthy = value; } |
213 | |
214 | static bool isLocalHostOrLoopbackIPAddress(StringView); |
215 | |
216 | const SecurityOriginData& data() const { return m_data; } |
217 | |
218 | template<class Encoder> void encode(Encoder&) const; |
219 | template<class Decoder> static RefPtr<SecurityOrigin> decode(Decoder&); |
220 | |
221 | private: |
222 | SecurityOrigin(); |
223 | explicit SecurityOrigin(const URL&); |
224 | explicit SecurityOrigin(const SecurityOrigin*); |
225 | |
226 | // FIXME: Rename this function to something more semantic. |
227 | bool passesFileCheck(const SecurityOrigin&) const; |
228 | |
229 | // This method checks that the scheme for this origin is an HTTP-family |
230 | // scheme, e.g. HTTP and HTTPS. |
231 | bool isHTTPFamily() const { return m_data.protocol == "http" || m_data.protocol == "https" ; } |
232 | |
233 | enum ShouldAllowFromThirdParty { AlwaysAllowFromThirdParty, MaybeAllowFromThirdParty }; |
234 | WEBCORE_EXPORT bool canAccessStorage(const SecurityOrigin*, ShouldAllowFromThirdParty = MaybeAllowFromThirdParty) const; |
235 | |
236 | SecurityOriginData m_data; |
237 | String m_domain; |
238 | String m_filePath; |
239 | bool m_isUnique { false }; |
240 | bool m_universalAccess { false }; |
241 | bool m_domainWasSetInDOM { false }; |
242 | bool m_canLoadLocalResources { false }; |
243 | StorageBlockingPolicy m_storageBlockingPolicy { AllowAllStorage }; |
244 | bool m_enforcesFilePathSeparation { false }; |
245 | bool m_needsStorageAccessFromFileURLsQuirk { false }; |
246 | bool m_isPotentiallyTrustworthy { false }; |
247 | bool m_isLocal { false }; |
248 | }; |
249 | |
250 | bool shouldTreatAsPotentiallyTrustworthy(const URL&); |
251 | |
252 | // Returns true if the Origin header values serialized from these two origins would be the same. |
253 | bool serializedOriginsMatch(const SecurityOrigin&, const SecurityOrigin&); |
254 | bool serializedOriginsMatch(const SecurityOrigin*, const SecurityOrigin*); |
255 | |
256 | template<class Encoder> inline void SecurityOrigin::encode(Encoder& encoder) const |
257 | { |
258 | encoder << m_data; |
259 | encoder << m_domain; |
260 | encoder << m_filePath; |
261 | encoder << m_isUnique; |
262 | encoder << m_universalAccess; |
263 | encoder << m_domainWasSetInDOM; |
264 | encoder << m_canLoadLocalResources; |
265 | encoder.encodeEnum(m_storageBlockingPolicy); |
266 | encoder << m_enforcesFilePathSeparation; |
267 | encoder << m_needsStorageAccessFromFileURLsQuirk; |
268 | encoder << m_isPotentiallyTrustworthy; |
269 | encoder << m_isLocal; |
270 | } |
271 | |
272 | template<class Decoder> inline RefPtr<SecurityOrigin> SecurityOrigin::decode(Decoder& decoder) |
273 | { |
274 | Optional<SecurityOriginData> data; |
275 | decoder >> data; |
276 | if (!data) |
277 | return nullptr; |
278 | |
279 | auto origin = SecurityOrigin::create(data->protocol, data->host, data->port); |
280 | |
281 | if (!decoder.decode(origin->m_domain)) |
282 | return nullptr; |
283 | if (!decoder.decode(origin->m_filePath)) |
284 | return nullptr; |
285 | if (!decoder.decode(origin->m_isUnique)) |
286 | return nullptr; |
287 | if (!decoder.decode(origin->m_universalAccess)) |
288 | return nullptr; |
289 | if (!decoder.decode(origin->m_domainWasSetInDOM)) |
290 | return nullptr; |
291 | if (!decoder.decode(origin->m_canLoadLocalResources)) |
292 | return nullptr; |
293 | if (!decoder.decodeEnum(origin->m_storageBlockingPolicy)) |
294 | return nullptr; |
295 | if (!decoder.decode(origin->m_enforcesFilePathSeparation)) |
296 | return nullptr; |
297 | if (!decoder.decode(origin->m_needsStorageAccessFromFileURLsQuirk)) |
298 | return nullptr; |
299 | if (!decoder.decode(origin->m_isPotentiallyTrustworthy)) |
300 | return nullptr; |
301 | if (!decoder.decode(origin->m_isLocal)) |
302 | return nullptr; |
303 | |
304 | return origin; |
305 | } |
306 | |
307 | } // namespace WebCore |
308 | |