Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(614)

Side by Side Diff: Source/platform/weborigin/SecurityOrigin.cpp

Issue 27073003: CSP Suborigins Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Test fixes Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 19 matching lines...) Expand all
30 #include "platform/weborigin/SecurityOrigin.h" 30 #include "platform/weborigin/SecurityOrigin.h"
31 31
32 #include "platform/weborigin/KURL.h" 32 #include "platform/weborigin/KURL.h"
33 #include "platform/weborigin/KnownPorts.h" 33 #include "platform/weborigin/KnownPorts.h"
34 #include "platform/weborigin/SchemeRegistry.h" 34 #include "platform/weborigin/SchemeRegistry.h"
35 #include "platform/weborigin/SecurityOriginCache.h" 35 #include "platform/weborigin/SecurityOriginCache.h"
36 #include "platform/weborigin/SecurityPolicy.h" 36 #include "platform/weborigin/SecurityPolicy.h"
37 #include "url/url_canon_ip.h" 37 #include "url/url_canon_ip.h"
38 #include "wtf/HexNumber.h" 38 #include "wtf/HexNumber.h"
39 #include "wtf/MainThread.h" 39 #include "wtf/MainThread.h"
40 #include "wtf/NotFound.h"
40 #include "wtf/StdLibExtras.h" 41 #include "wtf/StdLibExtras.h"
41 #include "wtf/text/StringBuilder.h" 42 #include "wtf/text/StringBuilder.h"
42 43
43 namespace blink { 44 namespace blink {
44 45
45 const int InvalidPort = 0; 46 const int InvalidPort = 0;
46 const int MaxAllowedPort = 65535; 47 const int MaxAllowedPort = 65535;
47 48
48 static SecurityOriginCache* s_originCache = 0; 49 static SecurityOriginCache* s_originCache = 0;
49 50
50 static bool schemeRequiresAuthority(const KURL& url) 51 static bool schemeRequiresAuthority(const KURL& url)
51 { 52 {
52 // We expect URLs with these schemes to have authority components. If the 53 // 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 54 // URL lacks an authority component, we get concerned and mark the origin
54 // as unique. 55 // as unique.
55 return url.protocolIsInHTTPFamily() || url.protocolIs("ftp"); 56 return url.protocolIsInHTTPFamily() || url.protocolIs("ftp");
56 } 57 }
57 58
58 static SecurityOrigin* cachedOrigin(const KURL& url) 59 static SecurityOrigin* cachedOrigin(const KURL& url)
59 { 60 {
60 if (s_originCache) 61 if (s_originCache)
61 return s_originCache->cachedOrigin(url); 62 return s_originCache->cachedOrigin(url);
62 return 0; 63 return 0;
63 } 64 }
64 65
66 static bool sameSuborigin(const SecurityOrigin* origin1, const SecurityOrigin* o rigin2)
67 {
68 // If either origin has a suborigin set, both must have the same suborigin.
69 return origin1->suboriginName() == origin2->suboriginName();
70 }
71
65 bool SecurityOrigin::shouldUseInnerURL(const KURL& url) 72 bool SecurityOrigin::shouldUseInnerURL(const KURL& url)
66 { 73 {
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. 74 // 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")) 75 if (url.protocolIs("blob"))
69 return true; 76 return true;
70 if (url.protocolIs("filesystem")) 77 if (url.protocolIs("filesystem"))
71 return true; 78 return true;
72 return false; 79 return false;
73 } 80 }
74 81
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 // that assume the scheme has already been canonicalized. 116 // that assume the scheme has already been canonicalized.
110 String protocol = innerURL.protocol().lower(); 117 String protocol = innerURL.protocol().lower();
111 118
112 if (SchemeRegistry::shouldTreatURLSchemeAsNoAccess(protocol)) 119 if (SchemeRegistry::shouldTreatURLSchemeAsNoAccess(protocol))
113 return true; 120 return true;
114 121
115 // This is the common case. 122 // This is the common case.
116 return false; 123 return false;
117 } 124 }
118 125
126 bool deserializeSuboriginAndProtocol(const String& oldProtocol, String& suborigi nName, String& newProtocol)
127 {
128 const char suboriginPrefix[] = "suborigin+";
129 if (!oldProtocol.startsWith(suboriginPrefix))
130 return false;
131
132 size_t suboriginStart = strlen(suboriginPrefix);
133 size_t protocolStart = oldProtocol.find('+', suboriginStart + 1);
134
135 if (protocolStart == kNotFound)
136 return false;
137
138 suboriginName = oldProtocol.substring(suboriginStart, protocolStart - subori ginStart);
139 newProtocol = oldProtocol.substring(protocolStart + 1);
140
Mike West 2015/03/23 07:32:56 ASSERT that the runtime-enabled feature is enabled
jww 2015/04/11 02:52:36 I instead put a check at the top to make sure we o
141 return true;
142 }
143
119 SecurityOrigin::SecurityOrigin(const KURL& url) 144 SecurityOrigin::SecurityOrigin(const KURL& url)
120 : m_protocol(url.protocol().isNull() ? "" : url.protocol().lower()) 145 : m_protocol(url.protocol().isNull() ? "" : url.protocol().lower())
121 , m_host(url.host().isNull() ? "" : url.host().lower()) 146 , m_host(url.host().isNull() ? "" : url.host().lower())
122 , m_port(url.port()) 147 , m_port(url.port())
123 , m_isUnique(false) 148 , m_isUnique(false)
124 , m_universalAccess(false) 149 , m_universalAccess(false)
125 , m_domainWasSetInDOM(false) 150 , m_domainWasSetInDOM(false)
126 , m_enforceFilePathSeparation(false) 151 , m_enforceFilePathSeparation(false)
127 , m_needsDatabaseIdentifierQuirkForFiles(false) 152 , m_needsDatabaseIdentifierQuirkForFiles(false)
128 { 153 {
154 // Suborigins are serialized into the protocol, so extract it if necessary.
155 String suboriginName;
156 if (deserializeSuboriginAndProtocol(m_protocol, suboriginName, m_protocol))
Mike West 2015/03/23 07:32:55 A side-effect of lumping the suborigin into the pr
jww 2015/04/25 00:41:22 Agreed. For this original implementation, my idea
157 addSuborigin(suboriginName);
158
129 // document.domain starts as m_host, but can be set by the DOM. 159 // document.domain starts as m_host, but can be set by the DOM.
130 m_domain = m_host; 160 m_domain = m_host;
131 161
132 if (isDefaultPortForProtocol(m_port, m_protocol)) 162 if (isDefaultPortForProtocol(m_port, m_protocol))
133 m_port = InvalidPort; 163 m_port = InvalidPort;
134 164
135 // By default, only local SecurityOrigins can load local resources. 165 // By default, only local SecurityOrigins can load local resources.
136 m_canLoadLocalResources = isLocal(); 166 m_canLoadLocalResources = isLocal();
137 167
138 if (m_canLoadLocalResources) 168 if (m_canLoadLocalResources)
(...skipping 12 matching lines...) Expand all
151 , m_enforceFilePathSeparation(false) 181 , m_enforceFilePathSeparation(false)
152 , m_needsDatabaseIdentifierQuirkForFiles(false) 182 , m_needsDatabaseIdentifierQuirkForFiles(false)
153 { 183 {
154 } 184 }
155 185
156 SecurityOrigin::SecurityOrigin(const SecurityOrigin* other) 186 SecurityOrigin::SecurityOrigin(const SecurityOrigin* other)
157 : m_protocol(other->m_protocol.isolatedCopy()) 187 : m_protocol(other->m_protocol.isolatedCopy())
158 , m_host(other->m_host.isolatedCopy()) 188 , m_host(other->m_host.isolatedCopy())
159 , m_domain(other->m_domain.isolatedCopy()) 189 , m_domain(other->m_domain.isolatedCopy())
160 , m_filePath(other->m_filePath.isolatedCopy()) 190 , m_filePath(other->m_filePath.isolatedCopy())
191 , m_suboriginName(other->m_suboriginName)
161 , m_port(other->m_port) 192 , m_port(other->m_port)
162 , m_isUnique(other->m_isUnique) 193 , m_isUnique(other->m_isUnique)
163 , m_universalAccess(other->m_universalAccess) 194 , m_universalAccess(other->m_universalAccess)
164 , m_domainWasSetInDOM(other->m_domainWasSetInDOM) 195 , m_domainWasSetInDOM(other->m_domainWasSetInDOM)
165 , m_canLoadLocalResources(other->m_canLoadLocalResources) 196 , m_canLoadLocalResources(other->m_canLoadLocalResources)
166 , m_enforceFilePathSeparation(other->m_enforceFilePathSeparation) 197 , m_enforceFilePathSeparation(other->m_enforceFilePathSeparation)
167 , m_needsDatabaseIdentifierQuirkForFiles(other->m_needsDatabaseIdentifierQui rkForFiles) 198 , m_needsDatabaseIdentifierQuirkForFiles(other->m_needsDatabaseIdentifierQui rkForFiles)
168 { 199 {
169 } 200 }
170 201
(...skipping 22 matching lines...) Expand all
193 return adoptRef(new SecurityOrigin(url)); 224 return adoptRef(new SecurityOrigin(url));
194 } 225 }
195 226
196 PassRefPtr<SecurityOrigin> SecurityOrigin::createUnique() 227 PassRefPtr<SecurityOrigin> SecurityOrigin::createUnique()
197 { 228 {
198 RefPtr<SecurityOrigin> origin = adoptRef(new SecurityOrigin()); 229 RefPtr<SecurityOrigin> origin = adoptRef(new SecurityOrigin());
199 ASSERT(origin->isUnique()); 230 ASSERT(origin->isUnique());
200 return origin.release(); 231 return origin.release();
201 } 232 }
202 233
234 void SecurityOrigin::addSuborigin(const String& suborigin)
235 {
236 // Changing suborigins midstream is bad. Very bad. It should not happen.
237 // This is, in fact, one of the very basic invariants that makes suborigins
238 // an effective security tool.
Mike West 2015/03/23 07:32:56 ASSERT that the runtime-enabled feature is enabled
jww 2015/04/11 02:52:36 Done.
239 RELEASE_ASSERT(m_suboriginName.isNull() || m_suboriginName == suborigin);
Mike West 2015/03/23 07:32:55 When would the suborigin be set to itself? Could w
jww 2015/04/11 02:52:36 There are some cases, I believe during script exec
240 m_suboriginName = suborigin;
Mike West 2015/03/23 07:32:55 Please add unit tests for this change. You can ver
jww 2015/04/11 02:52:36 Done.
241 }
242
203 PassRefPtr<SecurityOrigin> SecurityOrigin::isolatedCopy() const 243 PassRefPtr<SecurityOrigin> SecurityOrigin::isolatedCopy() const
204 { 244 {
205 return adoptRef(new SecurityOrigin(this)); 245 return adoptRef(new SecurityOrigin(this));
206 } 246 }
207 247
208 void SecurityOrigin::setDomainFromDOM(const String& newDomain) 248 void SecurityOrigin::setDomainFromDOM(const String& newDomain)
209 { 249 {
210 m_domainWasSetInDOM = true; 250 m_domainWasSetInDOM = true;
211 m_domain = newDomain.lower(); 251 m_domain = newDomain.lower();
212 } 252 }
(...skipping 15 matching lines...) Expand all
228 { 268 {
229 if (m_universalAccess) 269 if (m_universalAccess)
230 return true; 270 return true;
231 271
232 if (this == other) 272 if (this == other)
233 return true; 273 return true;
234 274
235 if (isUnique() || other->isUnique()) 275 if (isUnique() || other->isUnique())
236 return false; 276 return false;
237 277
278 if (!sameSuborigin(this, other))
279 return false;
Mike West 2015/03/23 07:32:56 Please add unit tests for this change.
jww 2015/04/11 02:52:36 Done.
280
238 // Here are two cases where we should permit access: 281 // Here are two cases where we should permit access:
239 // 282 //
240 // 1) Neither document has set document.domain. In this case, we insist 283 // 1) Neither document has set document.domain. In this case, we insist
241 // that the scheme, host, and port of the URLs match. 284 // that the scheme, host, and port of the URLs match.
242 // 285 //
243 // 2) Both documents have set document.domain. In this case, we insist 286 // 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 287 // that the documents have set document.domain to the same value and
245 // that the scheme of the URLs match. 288 // that the scheme of the URLs match.
246 // 289 //
247 // This matches the behavior of Firefox 2 and Internet Explorer 6. 290 // This matches the behavior of Firefox 2 and Internet Explorer 6.
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
291 return true; 334 return true;
292 335
293 if (isUnique()) 336 if (isUnique())
294 return false; 337 return false;
295 338
296 RefPtr<SecurityOrigin> targetOrigin = SecurityOrigin::create(url); 339 RefPtr<SecurityOrigin> targetOrigin = SecurityOrigin::create(url);
297 340
298 if (targetOrigin->isUnique()) 341 if (targetOrigin->isUnique())
299 return false; 342 return false;
300 343
344 if (!sameSuborigin(this, targetOrigin.get()))
Mike West 2015/03/23 07:32:55 Please add unit tests for this change. It seems l
jww 2015/04/11 02:52:36 Added.
345 return false;
346
301 // We call isSameSchemeHostPort here instead of canAccess because we want 347 // We call isSameSchemeHostPort here instead of canAccess because we want
302 // to ignore document.domain effects. 348 // to ignore document.domain effects.
303 if (isSameSchemeHostPort(targetOrigin.get())) 349 if (isSameSchemeHostPort(targetOrigin.get()))
304 return true; 350 return true;
305 351
306 if (SecurityPolicy::isAccessWhiteListed(this, targetOrigin.get())) 352 if (SecurityPolicy::isAccessWhiteListed(this, targetOrigin.get()))
307 return true; 353 return true;
308 354
309 return false; 355 return false;
310 } 356 }
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
385 errorMessage = "Only secure origins are allowed. http://goo.gl/lq4gCo"; 431 errorMessage = "Only secure origins are allowed. http://goo.gl/lq4gCo";
386 return false; 432 return false;
387 } 433 }
388 434
389 SecurityOrigin::Policy SecurityOrigin::canShowNotifications() const 435 SecurityOrigin::Policy SecurityOrigin::canShowNotifications() const
390 { 436 {
391 if (m_universalAccess) 437 if (m_universalAccess)
392 return AlwaysAllow; 438 return AlwaysAllow;
393 if (isUnique()) 439 if (isUnique())
394 return AlwaysDeny; 440 return AlwaysDeny;
441 if (hasSuborigin())
442 return AlwaysDeny;
Mike West 2015/03/23 07:32:55 There's no test for this behavioral change. Please
jww 2015/04/11 02:52:36 Done.
395 return Ask; 443 return Ask;
396 } 444 }
397 445
398 void SecurityOrigin::grantLoadLocalResources() 446 void SecurityOrigin::grantLoadLocalResources()
399 { 447 {
400 // Granting privileges to some, but not all, documents in a SecurityOrigin 448 // Granting privileges to some, but not all, documents in a SecurityOrigin
401 // is a security hazard because the documents without the privilege can 449 // is a security hazard because the documents without the privilege can
402 // obtain the privilege by injecting script into the documents that have 450 // obtain the privilege by injecting script into the documents that have
403 // been granted the privilege. 451 // been granted the privilege.
404 m_canLoadLocalResources = true; 452 m_canLoadLocalResources = true;
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
474 AtomicString SecurityOrigin::toRawAtomicString() const 522 AtomicString SecurityOrigin::toRawAtomicString() const
475 { 523 {
476 if (m_protocol == "file") 524 if (m_protocol == "file")
477 return AtomicString("file://", AtomicString::ConstructFromLiteral); 525 return AtomicString("file://", AtomicString::ConstructFromLiteral);
478 526
479 StringBuilder result; 527 StringBuilder result;
480 buildRawString(result); 528 buildRawString(result);
481 return result.toAtomicString(); 529 return result.toAtomicString();
482 } 530 }
483 531
484 inline void SecurityOrigin::buildRawString(StringBuilder& builder) const 532 inline void SecurityOrigin::buildRawString(StringBuilder& builder) const
Mike West 2015/03/23 07:32:55 Please add unit tests for the new behavior here.
485 { 533 {
486 builder.reserveCapacity(m_protocol.length() + m_host.length() + 10); 534 if (hasSuborigin()) {
535 builder.reserveCapacity(11 + m_suboriginName.length() + m_protocol.lengt h() + m_host.length() + 10);
536 builder.appendLiteral("suborigin+");
537 builder.append(m_suboriginName);
538 builder.append('+');
Mike West 2015/03/23 07:32:55 This is very strange syntax.
jww 2015/04/11 02:52:36 Initially I went with ':', but this causes all sor
539 } else {
540 builder.reserveCapacity(m_protocol.length() + m_host.length() + 10);
541 }
487 builder.append(m_protocol); 542 builder.append(m_protocol);
488 builder.appendLiteral("://"); 543 builder.appendLiteral("://");
489 builder.append(m_host); 544 builder.append(m_host);
490 545
491 if (m_port) { 546 if (m_port) {
492 builder.append(':'); 547 builder.append(':');
493 builder.appendNumber(m_port); 548 builder.appendNumber(m_port);
494 } 549 }
495 } 550 }
496 551
497 PassRefPtr<SecurityOrigin> SecurityOrigin::createFromString(const String& origin String) 552 PassRefPtr<SecurityOrigin> SecurityOrigin::createFromString(const String& origin String)
498 { 553 {
499 return SecurityOrigin::create(KURL(KURL(), originString)); 554 return SecurityOrigin::create(KURL(KURL(), originString));
500 } 555 }
501 556
502 PassRefPtr<SecurityOrigin> SecurityOrigin::create(const String& protocol, const String& host, int port) 557 PassRefPtr<SecurityOrigin> SecurityOrigin::create(const String& protocol, const String& host, int port)
503 { 558 {
504 if (port < 0 || port > MaxAllowedPort) 559 if (port < 0 || port > MaxAllowedPort)
505 return createUnique(); 560 return createUnique();
506 String decodedHost = decodeURLEscapeSequences(host); 561 String decodedHost = decodeURLEscapeSequences(host);
507 return create(KURL(KURL(), protocol + "://" + host + ":" + String::number(po rt) + "/")); 562 return create(KURL(KURL(), protocol + "://" + host + ":" + String::number(po rt) + "/"));
508 } 563 }
509 564
510 bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const 565 bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const
511 { 566 {
567 if (!sameSuborigin(this, other))
Mike West 2015/03/23 07:32:55 Do we always want the suborigin check when doing a
jww 2015/04/11 02:52:36 Even while it's experimental? It won't be a subori
568 return false;
569
512 if (m_host != other->m_host) 570 if (m_host != other->m_host)
513 return false; 571 return false;
514 572
515 if (m_protocol != other->m_protocol) 573 if (m_protocol != other->m_protocol)
516 return false; 574 return false;
517 575
518 if (m_port != other->m_port) 576 if (m_port != other->m_port)
519 return false; 577 return false;
520 578
521 if (isLocal() && !passesFileCheck(other)) 579 if (isLocal() && !passesFileCheck(other))
(...skipping 10 matching lines...) Expand all
532 } 590 }
533 591
534 void SecurityOrigin::transferPrivilegesFrom(const SecurityOrigin& origin) 592 void SecurityOrigin::transferPrivilegesFrom(const SecurityOrigin& origin)
535 { 593 {
536 m_universalAccess = origin.m_universalAccess; 594 m_universalAccess = origin.m_universalAccess;
537 m_canLoadLocalResources = origin.m_canLoadLocalResources; 595 m_canLoadLocalResources = origin.m_canLoadLocalResources;
538 m_enforceFilePathSeparation = origin.m_enforceFilePathSeparation; 596 m_enforceFilePathSeparation = origin.m_enforceFilePathSeparation;
539 } 597 }
540 598
541 } // namespace blink 599 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698