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
content / browser / service_worker / service_worker_security_utils.cc [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/service_worker/service_worker_security_utils.h"
#include "base/command_line.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/origin_util.h"
#include "content/public/common/url_constants.h"
#include "net/cookies/site_for_cookies.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
namespace content {
namespace service_worker_security_utils {
bool OriginCanRegisterServiceWorkerFromJavascript(const GURL& url) {
// WebUI service workers are always registered in C++.
if (url.SchemeIs(kChromeUIUntrustedScheme) || url.SchemeIs(kChromeUIScheme))
return false;
return OriginCanAccessServiceWorkers(url);
}
bool AllOriginsMatchAndCanAccessServiceWorkers(const std::vector<GURL>& urls) {
// (A) Check if all origins can access service worker. Every URL must be
// checked despite the same-origin check below in (B), because GetOrigin()
// uses the inner URL for filesystem URLs so that https://foo/ and
// filesystem:https://foo/ are considered equal, but filesystem URLs cannot
// access service worker.
for (const GURL& url : urls) {
if (!OriginCanAccessServiceWorkers(url))
return false;
}
// (B) Check if all origins are equal. Cross-origin access is permitted when
// --disable-web-security is set.
if (IsWebSecurityDisabled()) {
return true;
}
const GURL& first = urls.front();
for (const GURL& url : urls) {
if (first.DeprecatedGetOriginAsURL() != url.DeprecatedGetOriginAsURL())
return false;
}
return true;
}
bool IsWebSecurityDisabled() {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableWebSecurity);
}
void CheckOnUpdateUrls(const GURL& url, const blink::StorageKey& key) {
#if DCHECK_IS_ON()
const url::Origin origin_to_dcheck = url::Origin::Create(url);
DCHECK((origin_to_dcheck.opaque() && key.origin().opaque()) ||
origin_to_dcheck.IsSameOriginWith(key.origin()))
<< origin_to_dcheck << " and " << key.origin() << " should be equal.";
// TODO(crbug.com/40251360): verify that `top_frame_origin` matches the
// `top_level_site` of `storage_key`, in most cases.
//
// This is currently not the case if:
// - The storage key is not for the "real" top-level site, such as when the
// top-level site is actually an extension.
// - The storage key has a nonce, in which case its `top_level_site` will be
// for the frame that introduced the nonce (such as a fenced frame) and not
// the same as `top_level_site`.
// - The storage key was generated without third-party storage partitioning.
// This may be the case even when 3PSP is enabled, due to enterprise policy
// or deprecation trials.
//
// Consider adding a DHCECK here once the last of those conditions is
// resolved. See
// https://chromium-review.googlesource.com/c/chromium/src/+/4378900/4.
#endif
}
blink::StorageKey GetCorrectStorageKeyForWebSecurityState(
const blink::StorageKey& key,
const GURL& url) {
if (IsWebSecurityDisabled()) {
url::Origin other_origin = url::Origin::Create(url);
if (key.origin() != other_origin) {
return blink::StorageKey::CreateFirstParty(other_origin);
}
}
return key;
}
net::SiteForCookies site_for_cookies(const blink::StorageKey& key) {
// TODO(crbug.com/40737536): Once partitioning is on by default calling
// ToNetSiteForCookies will be sufficient.
return key.CopyWithForceEnabledThirdPartyStoragePartitioning()
.ToNetSiteForCookies();
}
} // namespace service_worker_security_utils
} // namespace content