OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2007 Apple Inc. All rights reserved. | 2 * Copyright (C) 2007 Apple 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 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 11 matching lines...) Expand all Loading... |
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 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 | 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 | 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 | 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. | 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 */ | 27 */ |
28 | 28 |
29 #include "config.h" | 29 #include "config.h" |
30 #include "platform/weborigin/SecurityOrigin.h" | 30 #include "platform/weborigin/SecurityOrigin.h" |
31 | 31 |
| 32 #include "platform/RuntimeEnabledFeatures.h" |
32 #include "platform/weborigin/KURL.h" | 33 #include "platform/weborigin/KURL.h" |
33 #include "platform/weborigin/KnownPorts.h" | 34 #include "platform/weborigin/KnownPorts.h" |
34 #include "platform/weborigin/SchemeRegistry.h" | 35 #include "platform/weborigin/SchemeRegistry.h" |
35 #include "platform/weborigin/SecurityOriginCache.h" | 36 #include "platform/weborigin/SecurityOriginCache.h" |
36 #include "platform/weborigin/SecurityPolicy.h" | 37 #include "platform/weborigin/SecurityPolicy.h" |
37 #include "url/url_canon_ip.h" | 38 #include "url/url_canon_ip.h" |
38 #include "wtf/HexNumber.h" | 39 #include "wtf/HexNumber.h" |
39 #include "wtf/MainThread.h" | 40 #include "wtf/MainThread.h" |
| 41 #include "wtf/NotFound.h" |
40 #include "wtf/StdLibExtras.h" | 42 #include "wtf/StdLibExtras.h" |
41 #include "wtf/text/StringBuilder.h" | 43 #include "wtf/text/StringBuilder.h" |
42 | 44 |
43 namespace blink { | 45 namespace blink { |
44 | 46 |
45 const int InvalidPort = 0; | 47 const int InvalidPort = 0; |
46 const int MaxAllowedPort = 65535; | 48 const int MaxAllowedPort = 65535; |
47 | 49 |
48 static SecurityOriginCache* s_originCache = 0; | 50 static SecurityOriginCache* s_originCache = 0; |
49 | 51 |
50 static bool schemeRequiresAuthority(const KURL& url) | 52 static bool schemeRequiresAuthority(const KURL& url) |
51 { | 53 { |
52 // We expect URLs with these schemes to have authority components. If the | 54 // We expect URLs with these schemes to have authority components. If the |
53 // URL lacks an authority component, we get concerned and mark the origin | 55 // URL lacks an authority component, we get concerned and mark the origin |
54 // as unique. | 56 // as unique. |
55 return url.protocolIsInHTTPFamily() || url.protocolIs("ftp"); | 57 return url.protocolIsInHTTPFamily() || url.protocolIs("ftp"); |
56 } | 58 } |
57 | 59 |
58 static SecurityOrigin* cachedOrigin(const KURL& url) | 60 static SecurityOrigin* cachedOrigin(const KURL& url) |
59 { | 61 { |
60 if (s_originCache) | 62 if (s_originCache) |
61 return s_originCache->cachedOrigin(url); | 63 return s_originCache->cachedOrigin(url); |
62 return 0; | 64 return 0; |
63 } | 65 } |
64 | 66 |
| 67 static bool sameSuborigin(const SecurityOrigin* origin1, const SecurityOrigin* o
rigin2) |
| 68 { |
| 69 // If either origin has a suborigin set, both must have the same suborigin. |
| 70 return origin1->suboriginName() == origin2->suboriginName(); |
| 71 } |
| 72 |
65 bool SecurityOrigin::shouldUseInnerURL(const KURL& url) | 73 bool SecurityOrigin::shouldUseInnerURL(const KURL& url) |
66 { | 74 { |
67 // FIXME: Blob URLs don't have inner URLs. Their form is "blob:<inner-origin
>/<UUID>", so treating the part after "blob:" as a URL is incorrect. | 75 // FIXME: Blob URLs don't have inner URLs. Their form is "blob:<inner-origin
>/<UUID>", so treating the part after "blob:" as a URL is incorrect. |
68 if (url.protocolIs("blob")) | 76 if (url.protocolIs("blob")) |
69 return true; | 77 return true; |
70 if (url.protocolIs("filesystem")) | 78 if (url.protocolIs("filesystem")) |
71 return true; | 79 return true; |
72 return false; | 80 return false; |
73 } | 81 } |
74 | 82 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 // that assume the scheme has already been canonicalized. | 117 // that assume the scheme has already been canonicalized. |
110 String protocol = innerURL.protocol().lower(); | 118 String protocol = innerURL.protocol().lower(); |
111 | 119 |
112 if (SchemeRegistry::shouldTreatURLSchemeAsNoAccess(protocol)) | 120 if (SchemeRegistry::shouldTreatURLSchemeAsNoAccess(protocol)) |
113 return true; | 121 return true; |
114 | 122 |
115 // This is the common case. | 123 // This is the common case. |
116 return false; | 124 return false; |
117 } | 125 } |
118 | 126 |
| 127 bool deserializeSuboriginAndProtocol(const String& oldProtocol, String& suborigi
nName, String& newProtocol) |
| 128 { |
| 129 if (!RuntimeEnabledFeatures::suboriginsEnabled()) |
| 130 return false; |
| 131 |
| 132 const char suboriginPrefix[] = "suborigin+"; |
| 133 if (!oldProtocol.startsWith(suboriginPrefix)) |
| 134 return false; |
| 135 |
| 136 size_t suboriginStart = strlen(suboriginPrefix); |
| 137 size_t protocolStart = oldProtocol.find('+', suboriginStart + 1); |
| 138 |
| 139 if (protocolStart == kNotFound) |
| 140 return false; |
| 141 |
| 142 suboriginName = oldProtocol.substring(suboriginStart, protocolStart - subori
ginStart); |
| 143 newProtocol = oldProtocol.substring(protocolStart + 1); |
| 144 |
| 145 return true; |
| 146 } |
| 147 |
119 SecurityOrigin::SecurityOrigin(const KURL& url) | 148 SecurityOrigin::SecurityOrigin(const KURL& url) |
120 : m_protocol(url.protocol().isNull() ? "" : url.protocol().lower()) | 149 : m_protocol(url.protocol().isNull() ? "" : url.protocol().lower()) |
121 , m_host(url.host().isNull() ? "" : url.host().lower()) | 150 , m_host(url.host().isNull() ? "" : url.host().lower()) |
122 , m_port(url.port()) | 151 , m_port(url.port()) |
123 , m_isUnique(false) | 152 , m_isUnique(false) |
124 , m_universalAccess(false) | 153 , m_universalAccess(false) |
125 , m_domainWasSetInDOM(false) | 154 , m_domainWasSetInDOM(false) |
126 , m_enforceFilePathSeparation(false) | 155 , m_enforceFilePathSeparation(false) |
127 , m_needsDatabaseIdentifierQuirkForFiles(false) | 156 , m_needsDatabaseIdentifierQuirkForFiles(false) |
128 { | 157 { |
| 158 // Suborigins are serialized into the protocol, so extract it if necessary. |
| 159 String suboriginName; |
| 160 if (deserializeSuboriginAndProtocol(m_protocol, suboriginName, m_protocol)) |
| 161 addSuborigin(suboriginName); |
| 162 |
129 // document.domain starts as m_host, but can be set by the DOM. | 163 // document.domain starts as m_host, but can be set by the DOM. |
130 m_domain = m_host; | 164 m_domain = m_host; |
131 | 165 |
132 if (isDefaultPortForProtocol(m_port, m_protocol)) | 166 if (isDefaultPortForProtocol(m_port, m_protocol)) |
133 m_port = InvalidPort; | 167 m_port = InvalidPort; |
134 | 168 |
135 // By default, only local SecurityOrigins can load local resources. | 169 // By default, only local SecurityOrigins can load local resources. |
136 m_canLoadLocalResources = isLocal(); | 170 m_canLoadLocalResources = isLocal(); |
137 | 171 |
138 if (m_canLoadLocalResources) | 172 if (m_canLoadLocalResources) |
(...skipping 12 matching lines...) Expand all Loading... |
151 , m_enforceFilePathSeparation(false) | 185 , m_enforceFilePathSeparation(false) |
152 , m_needsDatabaseIdentifierQuirkForFiles(false) | 186 , m_needsDatabaseIdentifierQuirkForFiles(false) |
153 { | 187 { |
154 } | 188 } |
155 | 189 |
156 SecurityOrigin::SecurityOrigin(const SecurityOrigin* other) | 190 SecurityOrigin::SecurityOrigin(const SecurityOrigin* other) |
157 : m_protocol(other->m_protocol.isolatedCopy()) | 191 : m_protocol(other->m_protocol.isolatedCopy()) |
158 , m_host(other->m_host.isolatedCopy()) | 192 , m_host(other->m_host.isolatedCopy()) |
159 , m_domain(other->m_domain.isolatedCopy()) | 193 , m_domain(other->m_domain.isolatedCopy()) |
160 , m_filePath(other->m_filePath.isolatedCopy()) | 194 , m_filePath(other->m_filePath.isolatedCopy()) |
| 195 , m_suboriginName(other->m_suboriginName) |
161 , m_port(other->m_port) | 196 , m_port(other->m_port) |
162 , m_isUnique(other->m_isUnique) | 197 , m_isUnique(other->m_isUnique) |
163 , m_universalAccess(other->m_universalAccess) | 198 , m_universalAccess(other->m_universalAccess) |
164 , m_domainWasSetInDOM(other->m_domainWasSetInDOM) | 199 , m_domainWasSetInDOM(other->m_domainWasSetInDOM) |
165 , m_canLoadLocalResources(other->m_canLoadLocalResources) | 200 , m_canLoadLocalResources(other->m_canLoadLocalResources) |
166 , m_enforceFilePathSeparation(other->m_enforceFilePathSeparation) | 201 , m_enforceFilePathSeparation(other->m_enforceFilePathSeparation) |
167 , m_needsDatabaseIdentifierQuirkForFiles(other->m_needsDatabaseIdentifierQui
rkForFiles) | 202 , m_needsDatabaseIdentifierQuirkForFiles(other->m_needsDatabaseIdentifierQui
rkForFiles) |
168 { | 203 { |
169 } | 204 } |
170 | 205 |
(...skipping 22 matching lines...) Expand all Loading... |
193 return adoptRef(new SecurityOrigin(url)); | 228 return adoptRef(new SecurityOrigin(url)); |
194 } | 229 } |
195 | 230 |
196 PassRefPtr<SecurityOrigin> SecurityOrigin::createUnique() | 231 PassRefPtr<SecurityOrigin> SecurityOrigin::createUnique() |
197 { | 232 { |
198 RefPtr<SecurityOrigin> origin = adoptRef(new SecurityOrigin()); | 233 RefPtr<SecurityOrigin> origin = adoptRef(new SecurityOrigin()); |
199 ASSERT(origin->isUnique()); | 234 ASSERT(origin->isUnique()); |
200 return origin.release(); | 235 return origin.release(); |
201 } | 236 } |
202 | 237 |
| 238 void SecurityOrigin::addSuborigin(const String& suborigin) |
| 239 { |
| 240 ASSERT(RuntimeEnabledFeatures::suboriginsEnabled()); |
| 241 // Changing suborigins midstream is bad. Very bad. It should not happen. |
| 242 // This is, in fact, one of the very basic invariants that makes suborigins |
| 243 // an effective security tool. |
| 244 RELEASE_ASSERT(m_suboriginName.isNull() || m_suboriginName == suborigin); |
| 245 m_suboriginName = suborigin; |
| 246 } |
| 247 |
203 PassRefPtr<SecurityOrigin> SecurityOrigin::isolatedCopy() const | 248 PassRefPtr<SecurityOrigin> SecurityOrigin::isolatedCopy() const |
204 { | 249 { |
205 return adoptRef(new SecurityOrigin(this)); | 250 return adoptRef(new SecurityOrigin(this)); |
206 } | 251 } |
207 | 252 |
208 void SecurityOrigin::setDomainFromDOM(const String& newDomain) | 253 void SecurityOrigin::setDomainFromDOM(const String& newDomain) |
209 { | 254 { |
210 m_domainWasSetInDOM = true; | 255 m_domainWasSetInDOM = true; |
211 m_domain = newDomain.lower(); | 256 m_domain = newDomain.lower(); |
212 } | 257 } |
(...skipping 15 matching lines...) Expand all Loading... |
228 { | 273 { |
229 if (m_universalAccess) | 274 if (m_universalAccess) |
230 return true; | 275 return true; |
231 | 276 |
232 if (this == other) | 277 if (this == other) |
233 return true; | 278 return true; |
234 | 279 |
235 if (isUnique() || other->isUnique()) | 280 if (isUnique() || other->isUnique()) |
236 return false; | 281 return false; |
237 | 282 |
| 283 if (!sameSuborigin(this, other)) |
| 284 return false; |
| 285 |
238 // Here are two cases where we should permit access: | 286 // Here are two cases where we should permit access: |
239 // | 287 // |
240 // 1) Neither document has set document.domain. In this case, we insist | 288 // 1) Neither document has set document.domain. In this case, we insist |
241 // that the scheme, host, and port of the URLs match. | 289 // that the scheme, host, and port of the URLs match. |
242 // | 290 // |
243 // 2) Both documents have set document.domain. In this case, we insist | 291 // 2) Both documents have set document.domain. In this case, we insist |
244 // that the documents have set document.domain to the same value and | 292 // that the documents have set document.domain to the same value and |
245 // that the scheme of the URLs match. | 293 // that the scheme of the URLs match. |
246 // | 294 // |
247 // This matches the behavior of Firefox 2 and Internet Explorer 6. | 295 // This matches the behavior of Firefox 2 and Internet Explorer 6. |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
291 return true; | 339 return true; |
292 | 340 |
293 if (isUnique()) | 341 if (isUnique()) |
294 return false; | 342 return false; |
295 | 343 |
296 RefPtr<SecurityOrigin> targetOrigin = SecurityOrigin::create(url); | 344 RefPtr<SecurityOrigin> targetOrigin = SecurityOrigin::create(url); |
297 | 345 |
298 if (targetOrigin->isUnique()) | 346 if (targetOrigin->isUnique()) |
299 return false; | 347 return false; |
300 | 348 |
| 349 if (!sameSuborigin(this, targetOrigin.get())) |
| 350 return false; |
| 351 |
301 // We call isSameSchemeHostPort here instead of canAccess because we want | 352 // We call isSameSchemeHostPort here instead of canAccess because we want |
302 // to ignore document.domain effects. | 353 // to ignore document.domain effects. |
303 if (isSameSchemeHostPort(targetOrigin.get())) | 354 if (isSameSchemeHostPort(targetOrigin.get())) |
304 return true; | 355 return true; |
305 | 356 |
306 if (SecurityPolicy::isAccessWhiteListed(this, targetOrigin.get())) | 357 if (SecurityPolicy::isAccessWhiteListed(this, targetOrigin.get())) |
307 return true; | 358 return true; |
308 | 359 |
309 return false; | 360 return false; |
310 } | 361 } |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
385 errorMessage = "Only secure origins are allowed. http://goo.gl/lq4gCo"; | 436 errorMessage = "Only secure origins are allowed. http://goo.gl/lq4gCo"; |
386 return false; | 437 return false; |
387 } | 438 } |
388 | 439 |
389 SecurityOrigin::Policy SecurityOrigin::canShowNotifications() const | 440 SecurityOrigin::Policy SecurityOrigin::canShowNotifications() const |
390 { | 441 { |
391 if (m_universalAccess) | 442 if (m_universalAccess) |
392 return AlwaysAllow; | 443 return AlwaysAllow; |
393 if (isUnique()) | 444 if (isUnique()) |
394 return AlwaysDeny; | 445 return AlwaysDeny; |
| 446 if (hasSuborigin()) |
| 447 return AlwaysDeny; |
395 return Ask; | 448 return Ask; |
396 } | 449 } |
397 | 450 |
398 void SecurityOrigin::grantLoadLocalResources() | 451 void SecurityOrigin::grantLoadLocalResources() |
399 { | 452 { |
400 // Granting privileges to some, but not all, documents in a SecurityOrigin | 453 // Granting privileges to some, but not all, documents in a SecurityOrigin |
401 // is a security hazard because the documents without the privilege can | 454 // is a security hazard because the documents without the privilege can |
402 // obtain the privilege by injecting script into the documents that have | 455 // obtain the privilege by injecting script into the documents that have |
403 // been granted the privilege. | 456 // been granted the privilege. |
404 m_canLoadLocalResources = true; | 457 m_canLoadLocalResources = true; |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
476 if (m_protocol == "file") | 529 if (m_protocol == "file") |
477 return AtomicString("file://", AtomicString::ConstructFromLiteral); | 530 return AtomicString("file://", AtomicString::ConstructFromLiteral); |
478 | 531 |
479 StringBuilder result; | 532 StringBuilder result; |
480 buildRawString(result); | 533 buildRawString(result); |
481 return result.toAtomicString(); | 534 return result.toAtomicString(); |
482 } | 535 } |
483 | 536 |
484 inline void SecurityOrigin::buildRawString(StringBuilder& builder) const | 537 inline void SecurityOrigin::buildRawString(StringBuilder& builder) const |
485 { | 538 { |
486 builder.reserveCapacity(m_protocol.length() + m_host.length() + 10); | 539 if (hasSuborigin()) { |
| 540 builder.reserveCapacity(11 + m_suboriginName.length() + m_protocol.lengt
h() + m_host.length() + 10); |
| 541 builder.appendLiteral("suborigin+"); |
| 542 builder.append(m_suboriginName); |
| 543 builder.append('+'); |
| 544 } else { |
| 545 builder.reserveCapacity(m_protocol.length() + m_host.length() + 10); |
| 546 } |
487 builder.append(m_protocol); | 547 builder.append(m_protocol); |
488 builder.appendLiteral("://"); | 548 builder.appendLiteral("://"); |
489 builder.append(m_host); | 549 builder.append(m_host); |
490 | 550 |
491 if (m_port) { | 551 if (m_port) { |
492 builder.append(':'); | 552 builder.append(':'); |
493 builder.appendNumber(m_port); | 553 builder.appendNumber(m_port); |
494 } | 554 } |
495 } | 555 } |
496 | 556 |
497 PassRefPtr<SecurityOrigin> SecurityOrigin::createFromString(const String& origin
String) | 557 PassRefPtr<SecurityOrigin> SecurityOrigin::createFromString(const String& origin
String) |
498 { | 558 { |
499 return SecurityOrigin::create(KURL(KURL(), originString)); | 559 return SecurityOrigin::create(KURL(KURL(), originString)); |
500 } | 560 } |
501 | 561 |
502 PassRefPtr<SecurityOrigin> SecurityOrigin::create(const String& protocol, const
String& host, int port) | 562 PassRefPtr<SecurityOrigin> SecurityOrigin::create(const String& protocol, const
String& host, int port) |
503 { | 563 { |
504 if (port < 0 || port > MaxAllowedPort) | 564 if (port < 0 || port > MaxAllowedPort) |
505 return createUnique(); | 565 return createUnique(); |
506 String decodedHost = decodeURLEscapeSequences(host); | 566 String decodedHost = decodeURLEscapeSequences(host); |
507 return create(KURL(KURL(), protocol + "://" + host + ":" + String::number(po
rt) + "/")); | 567 return create(KURL(KURL(), protocol + "://" + host + ":" + String::number(po
rt) + "/")); |
508 } | 568 } |
509 | 569 |
510 bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const | 570 bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const |
511 { | 571 { |
| 572 if (!sameSuborigin(this, other)) |
| 573 return false; |
| 574 |
512 if (m_host != other->m_host) | 575 if (m_host != other->m_host) |
513 return false; | 576 return false; |
514 | 577 |
515 if (m_protocol != other->m_protocol) | 578 if (m_protocol != other->m_protocol) |
516 return false; | 579 return false; |
517 | 580 |
518 if (m_port != other->m_port) | 581 if (m_port != other->m_port) |
519 return false; | 582 return false; |
520 | 583 |
521 if (isLocal() && !passesFileCheck(other)) | 584 if (isLocal() && !passesFileCheck(other)) |
(...skipping 10 matching lines...) Expand all Loading... |
532 } | 595 } |
533 | 596 |
534 void SecurityOrigin::transferPrivilegesFrom(const SecurityOrigin& origin) | 597 void SecurityOrigin::transferPrivilegesFrom(const SecurityOrigin& origin) |
535 { | 598 { |
536 m_universalAccess = origin.m_universalAccess; | 599 m_universalAccess = origin.m_universalAccess; |
537 m_canLoadLocalResources = origin.m_canLoadLocalResources; | 600 m_canLoadLocalResources = origin.m_canLoadLocalResources; |
538 m_enforceFilePathSeparation = origin.m_enforceFilePathSeparation; | 601 m_enforceFilePathSeparation = origin.m_enforceFilePathSeparation; |
539 } | 602 } |
540 | 603 |
541 } // namespace blink | 604 } // namespace blink |
OLD | NEW |