summaryrefslogtreecommitdiff
path: root/chromium/docs/security/origin-vs-url.md
blob: 25bc0e6f413e71bfa8f3aebda55879a9ec6cd223 (plain)
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# Use origin (rather than URL) for security decisions.

URLs are often not sufficient for security decisions, since the origin
may not be present in the URL (e.g., `about:blank`),
may be tricky to parse (e.g., `blob:` or `filesystem:` URLs),
or may be
[opaque](https://html.spec.whatwg.org/multipage/origin.html#concept-origin-opaque)
despite a normal-looking URL (e.g., the security context may be
[sandboxed](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-sandbox)).
Use origins whenever possible.


## Use `GetLastCommittedOrigin()` or `GetSecurityContext()`.

### Good

```c++
// Example of browser-side code.
content::RenderFrameHost* frame = ...;
if (safelist.Matches(frame->GetLastCommittedOrigin()) {
  // ...
}

// Example of renderer-side code.  Note that browser-side checks are still
// needed to ensure that a compromised renderer cannot bypass renderer-side-only
// checks.
blink::Frame* frame = ...;
if (safelist.Matches(frame->GetSecurityContext()->GetSecurityOrigin()) {
  // ...
}
```

### Bad

```c++
// Example of browser-side code.
content::RenderFrameHost* frame = ...;
if (safelist.Matches(frame->GetLastCommittedURL()) {
  // BUG: doesn't work for about:blank or sandboxed frames.
}

// Example of renderer-side code.  Note that browser-side checks are still
// needed to ensure that a compromised renderer cannot bypass renderer-side-only
// checks.
blink::LocalFrame* frame = ...;
if (safelist.Matches(frame->GetDocument()->Url()) {
  // BUG: doesn't work for about:blank or sandboxed frames.
  // BUG: doesn't work for RemoteFrame(s) which don't have a local Document
  //      object and don't know the URL (only the origin) of the frame.
}
```


## Don't use the `GURL` type to store origins.

`GURL origin` is an anti-pattern - representing origins as a URL-focused data
type means that 1) some information is lost (e.g., origin's nonce and precursor
information) and 2) some unnecessary information may be present (e.g., URL path
and/or query parts are never part of an origin).

Use the following datatypes to represent origins:

- C++: `url::Origin` or `blink::SecurityOrigin`
  (instead of `GURL` or `blink::KURL`).
- Mojo: `url.mojom.Origin`
  (instead of `url.mojom.Url`).
  Remember to
  [validate data](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/security/mojo.md#Validate-privilege_presuming-data-received-over-IPC)
  received over IPC from untrustworthy processes
  or even better
  [avoid sending origins](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/security/mojo.md#Do-not-send-unnecessary-or-privilege_presuming-data)
  in the first place.
- Java: `org.chromium.url.Origin`
  (see also `url::Origin::FromJavaObject`
  and `url::Origin::CreateJavaObject`).


## Avoid converting URLs to origins.

### Good

```c++
url::Origin origin = GetLastCommittedOrigin();
```

### Bad

```c++
GURL url = ...;
GURL origin = url.DeprecatedGetOriginAsURL();
// BUG: `origin` will be incorrect if `url` is an "about:blank" URL
// BUG: `origin` will be incorrect if `url` came from a sandboxed frame.
// BUG: `origin` will be incorrect when `url` (rather than
//      `base_url_for_data_url`) is used when working with loadDataWithBaseUrl
//      (see also https://crbug.com/1201514).
// BUG: `origin` will be empty if `url` is a blob: URL like
//      "blob:http://origin/guid-goes-here".
// NOTE: `GURL origin` is also an anti-pattern; see the "Use correct type to
//       represent origins" section below.

// Blink-specific example:
KURL url = ...;
scoped_refptr<SecurityOrigin> origin = SecurityOrigin::Create(url);
// BUG: `origin` will be incorrect if `url` is an "about:blank" URL
// BUG: `origin` will be incorrect if `url` came from a sandboxed frame.
```

### Risky

If you know what you are doing and really need to convert a URL into an origin,
then you can consider using `url::Origin::Create`, `url::SchemeHostPort`, or
`url::Origin::Resolve` (noting the limitations of those APIs - see below for
more details).

```c++
const GURL& url = ...;

// WARNING: `url::Origin::Create(url)` can give unexpected results if:
// 1) `url` is "about:blank", or "about:srcdoc"
//    (returning unique, opaque origin rather than the real origin of the frame)
// 2) `url` comes from a sandboxed frame
//    (potentially returning a non-opaque origin, when an opaque one is needed)
// 3) `base_url_for_data_url` should be used instead of `url`
//
// WARNING: `url::Origin::Create(url)` has some additional subtleties:
// 4) if `url` is a blob: or filesystem: URL like "blob:http://origin/blob-guid"
//    then the inner origin will be returned (unlike with `url::SchemeHostPort`)
// 5) data: URLs will be correctly be translated into opaque origins, but the
//    precursor origin will be lost (unlike with `url::Resolve`).
url::Origin origin = url::Origin::Create(url);

// WARNING: `url::SchemeHostPort(url)` will *mechanically* extract the scheme,
// host, and port of the URL, discarding other parts of the URL.  This may have
// unexpected results when:
// 1) `url` is "about:blank", or "about:srcdoc"
// 2) `url` comes from a sandboxed frame, i.e. when an opaque origin is expected
// 3) `url` is a data: URL, i.e. when an opaque origin is expected
// 4) `url` is a blob: or filesystem: URL like "blob:http://origin/blob-guid"
//    (the inner origin will *not* be returned - unlike `url::Origin::Create`)
url::SchemeHostPort scheme_host_port = url::SchemeHostPort(url);

// `url::Origin::Resolve` should work okay when:
// 1) `url` is "about:blank", or "about:srcdoc"
// 2) `url` comes from a sandboxed frame (i.e. when `base_origin` is opaque)
// 3) `url` is a data: URL (i.e. propagating precursor of `base_origin`)
// 4) `url` is a blob: or filesystem: URL like "blob:http://origin/blob-guid"
//
// WARNING: It is simpler and more robust to just use `GetLastCommittedOrigin`
// (instead of combining `GetLastCommittedOrigin` and `GetLastCommittedURL`
// using `url::Origin::Resolve`).
// WARNING: `url::Origin::Resolve` is unaware of `base_url_for_data_url`.
const url::Origin& base_origin = ...
url::Origin origin = url::Origin::Resolve(url, base_origin);
```