cookie是跟用户隐私、web安全有非常大的关联。 在必要的时候我们要使用cookie来完成开发,但是也要充分考虑在使用cookie时的安全性问题。
目前与cookie
安全性`相关的flag如下图:
分别是:
domain
path
expires
httpOnly
secure
sameSite
设置cookie
有两种方式,一种是通过document.cookie
这个前端api,第二种是通过http
的Set-Cookie
这个响应头。
domain
这个flag
控制cookie
的共享范围的要素之一。不管使用哪个方式设置cookie
,都应该在cookie
设置后,去看看cookie
设置之后的domain
值。
1 |
|
上面这份代码,会添加一个cookie
:
它的domain
是liuyunzhuge.com
。这个是一个不带.
作为前缀的domain
,所以这样的cookie
仅限制在liuyunzhuge.com
这个域下的页面可以访问。
换一下设置方式:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script>
document.cookie = 'test=foo; domain=liuyunzhuge.com;'
</script>
</body>
</html>
</html>
这种方式设置的cookie
,domain
会自动添加.
前缀:
有.
前缀的domain
,相应的cookie
在path
这个flag
也满足的前提下,可以共享给子域。比如上方的cookie
在访问http://a.liuyunzhuge.com:5500/client/html/demo.html
的时候,也能访问到。
domain
这个flag一定要注意它有没有.
前缀。如果你的业务,需要把cookie
共享给子域,那么.
就是必须的,如果你的业务不需要共享cookie
给子域,那一定不要给cookie的domain
设置.
前缀。
path
path
是控制cookie
作用范围的另一个要素。 默认情况下,cookie
被设置到当前文档所对应的目录:
比如上方的http://liuyunzhuge.com:5500/client/html/demo2.html
,会把cookie
设置到/client/html
这个path
。只有满足path
目录以及path
子目录的页面,才能访问path
对应的cookie
。比如/client/pages/demo.html
这个页面,就无法访问到path: /client/html
这个cookie
,但是/client/html/demo3.html
以及/client/html/sub/demo.html
是可以的。
document.cookie
也可以手动设置path
:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script>
document.cookie = 'test=foo; domain=liuyunzhuge.com; path=/'
</script>
</body>
</html>
</html>
虽然path
设置为/
很方便,同域的所有页面都能访问它,但是也增加了cookie
的作用范围,从而增加了额外的安全风险,所以在实际设置path
的时候,要根据它的真实业务范围来设定。
expires
expires
设置cookie
的生存时间。 默认情况下,如果不主动设置expires
,那么cookie
的生存周期就是session
级别的,与浏览器窗口的会话保持一直,当浏览器窗口关闭以后,这样的cookie
就会被自动清理。
可以通过max-age
或expires
两种方式来明确指定cookie
的生存时间:
max-age
指定一个整数,代表cookie
可以存活的秒数。 浏览器根据当前时间和max-age
来设定cookie
的expires
时间。所以max-age
是比较好使用的。expires
指定一个GMTString
来代表cookie
的准确失效时间,js中通过new Date().toUTCString()
可以把一个日期对象转换为GMTString
。
示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script>
document.cookie = 'test=foo; domain=liuyunzhuge.com; path=/; max-age=100'
</script>
</body>
</html>
</html>
expires
设置的越长,则越有被窃取和泄露的风险,所以cookie
的expires
也要合理设置。
httpOnly
httpOnly
这个flag
决定了cookie
不能被document.cookie
所访问,只能由http
来读写。 这对于保护cookie
不被XSS
攻击所窃取是很有用的,所以那些跟用户相关的很重要的cookie
一定要考虑是否添加httpOnly
的标记。
这个flag
也无法通过document.cookie
来设置。
secure
secure
这个flag
标识了cookie
只能在https
中使用,http
站点完全无法使用secure
这个flag
。
sameSite
这是一个新的flag
,较新的浏览器都已支持。它的作用是允许cookie
在跨站请求时不会被发送,从而阻止CSRF
攻击。假如你访问了某个存在CSRF
漏洞的一个网站A,并且这个网站的身份验证是基于cookie
的,接着你没有关闭浏览器,访问到了一个恶意网站B,它的页面里面有一个利用A网站CSRF
漏洞的请求;默认情况下,浏览器并不知道这个请求是恶意的,所以它会把这个请求按正常方式处理,比如携带你访问A时的cookie
,这样就导致CSRF
攻击成功。 sameSite
就是告诉浏览器有些cookie
在进行跨站请求时不要发送,从而去避免CSRF
攻击。
它有3个值:
none
这个值就是禁用sameSite
的意思;strict
这个值就是完全禁止跨站携带cookie
的意思;lax
在新版浏览器中,这个将成为默认选项。 这个值也有控制cookie
不要跨站发送的作用,但它不像strict
是严格控制的,这个值会允许部分跨站请求携带cookie
。比如链接跳转或iframe加载。
lax
是合理的。如果A站页面内有一个可跳转至B站页面的链接,如果点击这个链接,不能把B站页面的相关cookie
带过去,那么到了B站必然有些状态要重置。 典型的就是我博客内的这个github
链接,如果点击跳转到github
不能携带github
的cookie
,那么每次到了github
就都要重新登录。