1 | /* |
---|
2 | * Copyright (C) 2007 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 Computer, 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 | #include "config.h" |
---|
30 | #include "SecurityOrigin.h" |
---|
31 | |
---|
32 | #include "Document.h" |
---|
33 | #include "Frame.h" |
---|
34 | #include "FrameLoader.h" |
---|
35 | #include "FrameTree.h" |
---|
36 | #include "KURL.h" |
---|
37 | #include "PlatformString.h" |
---|
38 | |
---|
39 | namespace WebCore { |
---|
40 | |
---|
41 | static bool isDefaultPortForProtocol(unsigned short port, String protocol) |
---|
42 | { |
---|
43 | if (protocol.isEmpty()) |
---|
44 | return false; |
---|
45 | |
---|
46 | static HashMap<String, unsigned> defaultPorts; |
---|
47 | if (defaultPorts.isEmpty()) { |
---|
48 | defaultPorts.set("http", 80); |
---|
49 | defaultPorts.set("https", 443); |
---|
50 | defaultPorts.set("ftp", 21); |
---|
51 | defaultPorts.set("ftps", 990); |
---|
52 | } |
---|
53 | return defaultPorts.get(protocol) == port; |
---|
54 | } |
---|
55 | |
---|
56 | SecurityOrigin::SecurityOrigin(const String& protocol, const String& host, unsigned short port) |
---|
57 | : m_protocol(protocol.isNull() ? "" : protocol.lower()) |
---|
58 | , m_host(host.isNull() ? "" : host.lower()) |
---|
59 | , m_port(port) |
---|
60 | , m_portSet(port) |
---|
61 | , m_noAccess(false) |
---|
62 | , m_domainWasSetInDOM(false) |
---|
63 | { |
---|
64 | // These protocols do not create security origins; the owner frame provides the origin |
---|
65 | if (m_protocol == "about" || m_protocol == "javascript") |
---|
66 | m_protocol = ""; |
---|
67 | |
---|
68 | // data: URLs are not allowed access to anything other than themselves. |
---|
69 | if (m_protocol == "data") |
---|
70 | m_noAccess = true; |
---|
71 | |
---|
72 | |
---|
73 | if (isDefaultPortForProtocol(m_port, m_protocol)) { |
---|
74 | m_port = 0; |
---|
75 | m_portSet = false; |
---|
76 | } |
---|
77 | } |
---|
78 | |
---|
79 | bool SecurityOrigin::isEmpty() const |
---|
80 | { |
---|
81 | return m_protocol.isEmpty(); |
---|
82 | } |
---|
83 | |
---|
84 | PassRefPtr<SecurityOrigin> SecurityOrigin::create(const String& protocol, const String& host, unsigned short port, SecurityOrigin* ownerFrameOrigin) |
---|
85 | { |
---|
86 | RefPtr<SecurityOrigin> origin = new SecurityOrigin(protocol, host, port); |
---|
87 | |
---|
88 | // If we do not obtain a meaningful origin from the URL, then we try to find one |
---|
89 | // via the frame hierarchy. |
---|
90 | // We alias the SecurityOrigins to match Firefox, see Bug 15313 |
---|
91 | // http://bugs.webkit.org/show_bug.cgi?id=15313 |
---|
92 | if (origin->isEmpty() && ownerFrameOrigin) |
---|
93 | return ownerFrameOrigin; |
---|
94 | |
---|
95 | return origin.release(); |
---|
96 | } |
---|
97 | |
---|
98 | PassRefPtr<SecurityOrigin> SecurityOrigin::createForFrame(Frame* frame) |
---|
99 | { |
---|
100 | if (!frame) |
---|
101 | return create("", "", 0, 0); |
---|
102 | |
---|
103 | FrameLoader* loader = frame->loader(); |
---|
104 | KURL url = loader->url(); |
---|
105 | |
---|
106 | Frame* ownerFrame = frame->tree()->parent(); |
---|
107 | if (!ownerFrame) |
---|
108 | ownerFrame = loader->opener(); |
---|
109 | |
---|
110 | SecurityOrigin* ownerFrameOrigin = 0; |
---|
111 | if (ownerFrame && ownerFrame->document()) |
---|
112 | ownerFrameOrigin = ownerFrame->document()->securityOrigin(); |
---|
113 | |
---|
114 | return create(url.protocol(), url.host(), url.port(), ownerFrameOrigin); |
---|
115 | } |
---|
116 | |
---|
117 | PassRefPtr<SecurityOrigin> SecurityOrigin::copy() |
---|
118 | { |
---|
119 | return create(m_protocol.copy(), m_host.copy(), m_port, 0); |
---|
120 | } |
---|
121 | |
---|
122 | |
---|
123 | void SecurityOrigin::setDomainFromDOM(const String& newDomain) |
---|
124 | { |
---|
125 | m_domainWasSetInDOM = true; |
---|
126 | m_host = newDomain.lower(); |
---|
127 | } |
---|
128 | |
---|
129 | bool SecurityOrigin::canAccess(const SecurityOrigin* other, Reason& reason) const |
---|
130 | { |
---|
131 | if (FrameLoader::shouldTreatSchemeAsLocal(m_protocol)) |
---|
132 | return true; |
---|
133 | |
---|
134 | if (m_noAccess || other->m_noAccess) { |
---|
135 | reason = SecurityOrigin::GenericMismatch; |
---|
136 | return false; |
---|
137 | } |
---|
138 | |
---|
139 | // Here are three cases where we should permit access: |
---|
140 | // |
---|
141 | // 1) Neither document has set document.domain. In this case, we insist |
---|
142 | // that the scheme, host, and port of the URLs match. |
---|
143 | // |
---|
144 | // 2) Both documents have set document.domain. In this case, we insist |
---|
145 | // that the documents have set document.domain to the same value and |
---|
146 | // that the scheme of the URLs match. |
---|
147 | // |
---|
148 | // 3) As a special case if only one of the documents has set document.domain but |
---|
149 | // there is a host and port match we deny access but signal this to the client. |
---|
150 | // In this case Window::allowsAccessFrom() will recheck against the lexical global |
---|
151 | // object and allow access if that check passes. |
---|
152 | // |
---|
153 | // This matches the behavior of Firefox 2 and Internet Explorer 6. |
---|
154 | // |
---|
155 | // Internet Explorer 7 and Opera 9 are more strict in that they require |
---|
156 | // the port numbers to match when both pages have document.domain set. |
---|
157 | // |
---|
158 | // FIXME: Evaluate whether we can tighten this policy to require matched |
---|
159 | // port numbers. |
---|
160 | // |
---|
161 | // Opera 9 allows access when only one page has set document.domain, but |
---|
162 | // this is a security vulnerability. |
---|
163 | |
---|
164 | if (m_protocol == other->m_protocol) { |
---|
165 | if (!m_domainWasSetInDOM && !other->m_domainWasSetInDOM) { |
---|
166 | if (m_host == other->m_host && m_port == other->m_port) |
---|
167 | return true; |
---|
168 | } else if (m_domainWasSetInDOM && other->m_domainWasSetInDOM) { |
---|
169 | if (m_host == other->m_host) |
---|
170 | return true; |
---|
171 | } else { |
---|
172 | if (m_host == other->m_host && m_port == other->m_port) { |
---|
173 | reason = DomainSetInDOMMismatch; |
---|
174 | return false; |
---|
175 | } |
---|
176 | } |
---|
177 | } |
---|
178 | |
---|
179 | reason = SecurityOrigin::GenericMismatch; |
---|
180 | return false; |
---|
181 | } |
---|
182 | |
---|
183 | bool SecurityOrigin::isSecureTransitionTo(const KURL& url) const |
---|
184 | { |
---|
185 | // New window created by the application |
---|
186 | if (isEmpty()) |
---|
187 | return true; |
---|
188 | |
---|
189 | if (FrameLoader::shouldTreatSchemeAsLocal(m_protocol)) |
---|
190 | return true; |
---|
191 | |
---|
192 | return equalIgnoringCase(m_host, String(url.host())) && equalIgnoringCase(m_protocol, String(url.protocol())) && m_port == url.port(); |
---|
193 | } |
---|
194 | |
---|
195 | String SecurityOrigin::toString() const |
---|
196 | { |
---|
197 | return m_protocol + ":" + m_host + ":" + String::number(m_port); |
---|
198 | } |
---|
199 | |
---|
200 | static const char SeparatorCharacter = '_'; |
---|
201 | |
---|
202 | PassRefPtr<SecurityOrigin> SecurityOrigin::createFromIdentifier(const String& stringIdentifier) |
---|
203 | { |
---|
204 | // Make sure there's a first separator |
---|
205 | int separator1 = stringIdentifier.find(SeparatorCharacter); |
---|
206 | if (separator1 == -1) |
---|
207 | return create("", "", 0, 0); |
---|
208 | |
---|
209 | // Make sure there's a second separator |
---|
210 | int separator2 = stringIdentifier.find(SeparatorCharacter, separator1 + 1); |
---|
211 | if (separator2 == -1) |
---|
212 | return create("", "", 0, 0); |
---|
213 | |
---|
214 | // Make sure there's not a third separator |
---|
215 | if (stringIdentifier.reverseFind(SeparatorCharacter) != separator2) |
---|
216 | return create("", "", 0, 0); |
---|
217 | |
---|
218 | // Make sure the port section is a valid port number or doesn't exist |
---|
219 | bool portOkay; |
---|
220 | int port = stringIdentifier.right(stringIdentifier.length() - separator2 - 1).toInt(&portOkay); |
---|
221 | if (!portOkay && separator2 + 1 == static_cast<int>(stringIdentifier.length())) |
---|
222 | return create("", "", 0, 0); |
---|
223 | |
---|
224 | if (port < 0 || port > 65535) |
---|
225 | return create("", "", 0, 0); |
---|
226 | |
---|
227 | // Split out the 3 sections of data |
---|
228 | String protocol = stringIdentifier.substring(0, separator1); |
---|
229 | String host = stringIdentifier.substring(separator1 + 1, separator2 - separator1 - 1); |
---|
230 | return create(protocol, host, port, 0); |
---|
231 | } |
---|
232 | |
---|
233 | |
---|
234 | String SecurityOrigin::stringIdentifier() const |
---|
235 | { |
---|
236 | static String separatorString = String(&SeparatorCharacter, 1); |
---|
237 | return m_protocol + separatorString + m_host + separatorString + String::number(m_port); |
---|
238 | } |
---|
239 | |
---|
240 | } // namespace WebCore |
---|