|
2 | 2 |
|
3 | 3 | ## 概述
|
4 | 4 |
|
5 |
| -Cookie 是服务器保存在浏览器的一小段文本信息,每个 Cookie 的大小一般不能超过4KB。浏览器每次向服务器发出请求,就会自动附上这段信息。 |
| 5 | +Cookie 是服务器保存在浏览器的一小段文本信息,一般大小不能超过4KB。浏览器每次向服务器发出请求,就会自动附上这段信息。 |
6 | 6 |
|
7 |
| -Cookie 主要用来分辨两个请求是否来自同一个浏览器,以及用来保存一些状态信息。它的常用场合有以下一些。 |
| 7 | +Cookie 主要保存状态信息,以下是一些主要用途。 |
8 | 8 |
|
9 | 9 | - 对话(session)管理:保存登录、购物车等需要记录的信息。
|
10 |
| -- 个性化:保存用户的偏好,比如网页的字体大小、背景色等等。 |
11 |
| -- 追踪:记录和分析用户行为。 |
| 10 | +- 个性化信息:保存用户的偏好,比如网页的字体大小、背景色等等。 |
| 11 | +- 追踪用户:记录和分析用户行为。 |
12 | 12 |
|
13 |
| -有些开发者使用 Cookie 作为客户端储存。这样做虽然可行,但是并不推荐,因为 Cookie 的设计目标并不是这个,它的容量很小(4KB),缺乏数据操作接口,而且会影响性能。客户端储存应该使用 Web storage API 和 IndexedDB。 |
| 13 | +Cookie 不是一种理想的客户端储存机制。它的容量很小(4KB),缺乏数据操作接口,而且会影响性能。客户端储存应该使用 Web storage API 和 IndexedDB。只有那些每次请求都需要让服务器知道的信息,才应该放在 Cookie 里面。 |
14 | 14 |
|
15 |
| -Cookie 包含以下几方面的信息。 |
| 15 | +每个 Cookie 都有以下几方面的元数据。 |
16 | 16 |
|
17 | 17 | - Cookie 的名字
|
18 | 18 | - Cookie 的值(真正的数据写在这里面)
|
19 |
| -- 到期时间 |
20 |
| -- 所属域名(默认是当前域名) |
21 |
| -- 生效的路径(默认是当前网址) |
| 19 | +- 到期时间(超过这个时间会失效) |
| 20 | +- 所属域名(默认为当前域名) |
| 21 | +- 生效的路径(默认为当前网址) |
22 | 22 |
|
23 |
| -举例来说,用户访问网址`www.example.com`,服务器在浏览器写入一个 Cookie。这个 Cookie 就会包含`www.example.com`这个域名,以及根路径`/`。这意味着,这个 Cookie 对该域名的根路径和它的所有子路径都有效。如果路径设为`/forums`,那么这个 Cookie 只有在访问`www.example.com/forums`及其子路径时才有效。以后,浏览器一旦访问这个路径,浏览器就会附上这段 Cookie 发送给服务器。 |
| 23 | +举例来说,用户访问网址`www.example.com`,服务器在浏览器写入一个 Cookie。这个 Cookie 的所属域名为`www.example.com`,生效路径为根路径`/`。如果 Cookie 的生效路径设为`/forums`,那么这个 Cookie 只有在访问`www.example.com/forums`及其子路径时才有效。以后,浏览器访问某个路径之前,就会找出对该域名和路径有效,并且还没有到期的 Cookie,一起发送给服务器。 |
24 | 24 |
|
25 |
| -浏览器可以设置不接受 Cookie,也可以设置不向服务器发送 Cookie。`window.navigator.cookieEnabled`属性返回一个布尔值,表示浏览器是否打开 Cookie 功能。 |
| 25 | +用户可以设置浏览器不接受 Cookie,也可以设置不向服务器发送 Cookie。`window.navigator.cookieEnabled`属性返回一个布尔值,表示浏览器是否打开 Cookie 功能。 |
26 | 26 |
|
27 | 27 | ```javascript
|
28 |
| -// 浏览器是否打开 Cookie 功能 |
29 | 28 | window.navigator.cookieEnabled // true
|
30 | 29 | ```
|
31 | 30 |
|
32 | 31 | `document.cookie`属性返回当前网页的 Cookie。
|
33 | 32 |
|
34 | 33 | ```javascript
|
35 |
| -// 当前网页的 Cookie |
36 |
| -document.cookie |
| 34 | +document.cookie // "id=foo;key=bar" |
37 | 35 | ```
|
38 | 36 |
|
39 | 37 | 不同浏览器对 Cookie 数量和大小的限制,是不一样的。一般来说,单个域名设置的 Cookie 不应超过30个,每个 Cookie 的大小不能超过4KB。超过限制以后,Cookie 将被忽略,不会被设置。
|
@@ -181,6 +179,95 @@ Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;
|
181 | 179 |
|
182 | 180 | 上面是跨站点载入的一个恶意脚本的代码,能够将当前网页的 Cookie 发往第三方服务器。如果设置了一个 Cookie 的`HttpOnly`属性,上面代码就不会读到该 Cookie。
|
183 | 181 |
|
| 182 | +### SameSite |
| 183 | + |
| 184 | +Chrome 51 开始,浏览器的 Cookie 新增加了一个`SameSite`属性,用来防止 CSRF 攻击和用户追踪。 |
| 185 | + |
| 186 | +Cookie 往往用来存储用户的身份信息,恶意网站可以设法伪造带有正确 Cookie 的 HTTP 请求,这就是 CSRF 攻击。举例来说,用户登陆了银行网站`your-bank.com`,银行服务器发来了一个 Cookie。 |
| 187 | + |
| 188 | +```http |
| 189 | +Set-Cookie:id=a3fWa; |
| 190 | +``` |
| 191 | + |
| 192 | +用户后来又访问了恶意网站`malicious.com`,上面有一个表单。 |
| 193 | + |
| 194 | +```html |
| 195 | +<form action="your-bank.com/transfer" method="POST"> |
| 196 | + ... |
| 197 | +</form> |
| 198 | +``` |
| 199 | + |
| 200 | +用户一旦被诱骗发送这个表单,银行网站就会收到带有正确 Cookie 的请求。为了防止这种攻击,表单一般都带有一个随机 token,告诉服务器这是真实请求。 |
| 201 | + |
| 202 | +```html |
| 203 | +<form action="your-bank.com/transfer" method="POST"> |
| 204 | + <input type="hidden" name="token" value="dad3weg34"> |
| 205 | + ... |
| 206 | +</form> |
| 207 | +``` |
| 208 | + |
| 209 | +这种第三方网站引导发出的 Cookie,就称为第三方 Cookie。它除了用于 CSRF 攻击,还可以用于用户追踪。比如,Facebook 在第三方网站插入一张看不见的图片。 |
| 210 | + |
| 211 | +```html |
| 212 | +<img src="facebook.com" style="visibility:hidden;"> |
| 213 | +``` |
| 214 | + |
| 215 | +浏览器加载上面代码时,就会向 Facebook 发出带有 Cookie 的请求,从而 Facebook 就会知道你是谁,访问了什么网站。 |
| 216 | + |
| 217 | +Cookie 的`SameSite`属性用来限制第三方 Cookie,从而减少安全风险。它可以设置三个值。 |
| 218 | + |
| 219 | +> - Strict |
| 220 | +> - Lax |
| 221 | +> - None |
| 222 | +
|
| 223 | +**(1)Strict** |
| 224 | + |
| 225 | +`Strict`最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。 |
| 226 | + |
| 227 | +```http |
| 228 | +Set-Cookie: CookieName=CookieValue; SameSite=Strict; |
| 229 | +``` |
| 230 | + |
| 231 | +这个规则过于严格,可能造成非常不好的用户体验。比如,当前网页有一个 GitHub 链接,用户点击跳转就不会带有 GitHub 的 Cookie,跳转过去总是未登陆状态。 |
| 232 | + |
| 233 | +**(2)Lax** |
| 234 | + |
| 235 | +`Lax`规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外。 |
| 236 | + |
| 237 | +```html |
| 238 | +Set-Cookie: CookieName=CookieValue; SameSite=Lax; |
| 239 | +``` |
| 240 | + |
| 241 | +导航到目标网址的 GET 请求,只包括三种情况:链接,预加载请求,GET 表单。详见下表。 |
| 242 | + |
| 243 | +| 请求类型 | 示例 | 正常情况 | Lax | |
| 244 | +|-----------|:------------------------------------:|------------:|-------------| |
| 245 | +| 链接 | `<a href="..."></a>` | 发送 Cookie | 发送 Cookie | |
| 246 | +| 预加载 | `<link rel="prerender" href="..."/>` | 发送 Cookie | 发送 Cookie | |
| 247 | +| GET 表单 | `<form method="GET" action="...">` | 发送 Cookie | 发送 Cookie | |
| 248 | +| POST 表单 | `<form method="POST" action="...">` | 发送 Cookie | 不发送 | |
| 249 | +| iframe | `<iframe src="..."></iframe>` | 发送 Cookie | 不发送 | |
| 250 | +| AJAX | `$.get("...")` | 发送 Cookie | 不发送 | |
| 251 | +| Image | `<img src="...">` | 发送 Cookie | 不发送 | |
| 252 | + |
| 253 | +设置了`Strict`或`Lax`以后,基本就杜绝了 CSRF 攻击。当然,前提是用户浏览器支持 SameSite 属性。 |
| 254 | + |
| 255 | +**(3)None** |
| 256 | + |
| 257 | +Chrome 计划将`Lax`变为默认设置。这时,网站可以选择显式关闭`SameSite`属性,将其设为`None`。不过,前提是必须同时设置`Secure`属性(Cookie 只能通过 HTTPS 协议发送),否则无效。 |
| 258 | + |
| 259 | +下面的设置无效。 |
| 260 | + |
| 261 | +```text |
| 262 | +Set-Cookie: widget_session=abc123; SameSite=None |
| 263 | +``` |
| 264 | + |
| 265 | +下面的设置有效。 |
| 266 | + |
| 267 | +```text |
| 268 | +Set-Cookie: widget_session=abc123; SameSite=None; Secure |
| 269 | +``` |
| 270 | + |
184 | 271 | ## document.cookie
|
185 | 272 |
|
186 | 273 | `document.cookie`属性用于读写当前网页的 Cookie。
|
@@ -259,3 +346,8 @@ document.cookie = 'fontSize=;expires=Thu, 01-Jan-1970 00:00:01 GMT';
|
259 | 346 | ## 参考链接
|
260 | 347 |
|
261 | 348 | - [HTTP cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies), by MDN
|
| 349 | +- [Using the Same-Site Cookie Attribute to Prevent CSRF Attacks](https://www.netsparker.com/blog/web-security/same-site-cookie-attribute-prevent-cross-site-request-forgery/) |
| 350 | +- [SameSite cookies explained](https://web.dev/samesite-cookies-explained) |
| 351 | +- [Tough Cookies](https://scotthelme.co.uk/tough-cookies/), Scott Helme |
| 352 | +- [Cross-Site Request Forgery is dead!](https://scotthelme.co.uk/csrf-is-dead/), Scott Helme |
| 353 | + |
0 commit comments