什么是Set-Cookie


本文作者: jsweibo

本文链接: https://jsweibo.github.io/2019/03/24/%E4%BB%80%E4%B9%88%E6%98%AFSet-Cookie/

摘要

本文主要讲述了:

  1. 什么是 Set-Cookie
  2. 语法
  3. 写入一个 Cookie
  4. 写入多个 Cookie
  5. 指令

正文

服务器端通过Set-Cookie响应头在客户端写入 Cookie。

语法

1
2
3
4
5
6
7
8
9
10
11
12
13
Set-Cookie: <cookie-name>=<cookie-value>
Set-Cookie: <cookie-name>=<cookie-value>; Expires=<date>
Set-Cookie: <cookie-name>=<cookie-value>; Max-Age=<non-zero-digit>
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>
Set-Cookie: <cookie-name>=<cookie-value>; Path=<path-value>
Set-Cookie: <cookie-name>=<cookie-value>; Secure
Set-Cookie: <cookie-name>=<cookie-value>; HttpOnly

Set-Cookie: <cookie-name>=<cookie-value>; SameSite=Strict
Set-Cookie: <cookie-name>=<cookie-value>; SameSite=Lax

// 一次使用多个指令
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly

示例:

1
Set-Cookie: username=jsweibo

写入多个 Cookie 时只需要返回多个Set-Cookie即可。

示例:

1
2
Set-Cookie: username=jsweibo
Set-Cookie: age=18

指令

Expires 指令

服务器端可以使用Expires指令来设定 cookie 的到期时间。

Expires指令使用 GMT 时间。

如果不使用Expires指令。Cookie 将在浏览器被关闭之后自动到期。

如果使用了Expires指令。Cookie 将根据客户端时间来判断 cookie 是否到期。

示例:

1
Set-Cookie: username=jsweibo; Expires=Wed, 01 Jan 2020 00:00:00 GMT

Max-Age 指令

服务器端可以使用Max-Age指令来设定再过多少秒 cookie 过期。

如果同时设置Expires指令和Max-Age指令,Expires指令将被忽略。

示例:

1
Set-Cookie: username=jsweibo; Max-Age=60

HttpOnly 指令

服务器端可以使用HttpOnly指令禁止客户端使用document.cookie来读写此 Cookie。

示例:

1
Set-Cookie: username=jsweibo; HttpOnly

Secure 指令

服务器端可以使用Secure指令来指定客户端只在 https 请求时才发送 cookie 到服务器端。

注意:从 Firefox 52、Chrome 52 起,http 网站无法使用Secure指令。

示例:

1
Set-Cookie: username=jsweibo; Secure

Domain 指令

服务器端可以使用Domain指令来指定 cookie 的域名。

由于”同源政策 + Public Suffix List”的限制,浏览器端的 JavaScript 仅能读写部分第一方 cookie。

注意:cookie 的读写并未完全遵循同源政策。例如:

  • 允许a.example.com读写domain=.example.com的 cookie
  • 允许https://a.example.com读写http://a.example.com的 cookie,反之亦然
  • 允许http://a.example.com:81读写http://a.example.com:80的 cookie

在服务器响应头中,若不使用Domain指令,客户端将直接存储服务器的域名。

示例:

example.com

1
Set-Cookie: username=jsweibo

客户端会以username=jsweibo;Domain=example.com的形式存储。注意:此 cookie 无法被a.example.com读写。

在服务器响应头中,若使用Domain指令,客户端会在域名前添加.而后存储。

示例:

example.com

1
Set-Cookie: username=jsweibo;Domain=example.com

客户端会以username=jsweibo;Domain=.example.com的形式存储。注意:此 cookie 可被a.example.com读写。

Path 指令

服务器端可以使用Path指令来指定 cookie 的路径。

注意:只能向上读写。例如Path=/a的 cookie 可以被/a/b读写;Path=/a/b的 cookie 无法被/a读写

如果不使用此指令,默认取服务器文件的路径。

示例:

1
Set-Cookie: username=jsweibo; Path=/test

SameSite 指令

服务器端可以使用此指令设定是否在跨站请求时携带该 cookie。

注意:是否是跨站请求基于”Public Suffix List”判断。

示例:

测试环境:

example.com

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
document.cookie = 'jsweibo=123;domain=example.com;samesite=strict';
</script>
<script defer src="./js/index.js"></script>
<script defer src="//b.example.com/js/index.js"></script>
<script defer src="//example.com/js/index.js"></script>
<script defer src="//a.foo.com/js/index.js"></script>
<script defer src="//foo.com/js/index.js"></script>
</body>
</html>

由于”Public Suffix List”的限制,a.github.iogithub.io均无法写入domain=.github.io的 cookie,因此无法提供相应的测试环境。

结论:

  • a.example.com中通往b.example.com的网络请求不是a.example.com的跨站请求
  • a.example.com中通往example.com的网络请求不是a.example.com的跨站请求
  • a.example.com中通往a.foo.com的网络请求是a.example.com的跨站请求
  • a.example.com中通往foo.com的网络请求是a.example.com的跨站请求
  • a.github.io中通往b.github.io的网络请求是a.github.io的跨站请求
  • a.github.io中通往github.io的网络请求是a.github.io的跨站请求

SameSite指令有 3 种取值:

  • None
  • Strict
  • Lax

None

  • 在同站请求中携带该 cookie
  • 在跨站请求中携带该 cookie

注意:须配合Secure指令使用

Strict

  • 在同站请求中携带该 cookie
  • 在跨站请求中拒绝携带该 cookie

Lax

  • 在同站请求中携带该 cookie
  • 在页面跳转的跨站请求中(例如:<a>location.href)携带该 cookie,在其他的跨站请求中拒绝携带该 cookie

参考资料

本文作者: jsweibo

本文链接: https://jsweibo.github.io/2019/03/24/%E4%BB%80%E4%B9%88%E6%98%AFSet-Cookie/


本文对你有帮助?请支持我


支付宝
微信