cookie
cookie
是浏览器端的一种数据存储,常和localStorage
、session
一起比较,常被用来记录用户的身份信息状态,为无状态的http请求添加了访问用户的身份标志。只要满足了发送条件,就会自动添加到http请求头
中。满足条件是根据cookie的几个可选属性决定的,首先cookie是以键值对的方式存储(name = value
),每个键值对还有不同的可选属性,都可以在设置cookie时一并添加:
path
:可以访问cookie的页面路径,该路径及它的子路径都可以访问domain
:可以访问cookie的域名,该域名及它的子域名都可访问max-age
和expire
:都是设置cookie的存储周期,expire
是一个绝对的过期时间,以客户端为准,max-age
是一个相对存储时间。不设置超时时间的cookie存储周期为session,浏览器关闭后,cookie失效secure
:限制只能通过https
发送cookiehttpOnly
:限制只有http请求才能访问cookie,这样客户端脚本就不能读取cookie了,可以预防xss攻击
SameSite
:最开始由Chrome浏览器提出,现在已经得到了很多浏览器的支持,主要是用来防止csrf攻击
这些属性决定了cookie什么时候、什么场景下被使用。
设置cookie的方式
设置cookie的方式有两种,客户端和服务端,客户端通过document.cookie
设置,每次仅能对一个cookie进行设置和更新,可以参考MDN文档。服务端通过Set-Cookie响应头设置。需要注意的一点是cookie的domain
的默认值是服务端或客户端当前的域名,即使设置,也只能是当前域名及其父域名。
跨域cookie
前面说了,只要满足上面的可选属性,cookie就会自动被发送,但是有一种情况例外。就是当跨域请求发生时,浏览器默认不会携带cookie,即便cookie满足domain, path, secure
等属性。想要发送cookie需要分别在客户端和服务端进行相应的设置。
客户端需要添加携带cookie的标志:
1.ajax可以添加withCredentials: true
的选项
2.fetch可以添加credentials: 'include'
选项
服务端需要携带Access-Control-Allow-Credentials: true响应头,同时Access-Control-Allow-Origin
响应头不能为:*
通配符,只能指定具体的单一域名。
当然也可以使用代理来避免前后端跨域的问题。
SameSite属性
sameSite
属性在Chrome 51
开始添加,在Chrome 80
后将默认值设置为Lax
,主要用来限制跨站点cookie的发送情况。注意,这里的跨站和跨域是两个不同的定义。同站表示两个域名的二级域名+顶级域名相同。且顶级域名得是有效顶级域名(eTLD)
,有效顶级域名注册在 Mozilla
维护的公共后缀列表(Public Suffix List)中,例如.com, .co.uk, pvt.k12.ma.us
。所以a.baidu.com
和b.baidu.com
是同站,a.github.io
和b.github.io
不是同站,因为github.io
不属于有效顶级域名。
samesite
有三个值:
Strict
完全禁止跨站cookie的传递Lax
大多数情况不发送跨站cookie,具体如下
请求类型 | 示例 | 正常情况 | Lax |
---|---|---|---|
链接 | <a href="..."></a> | 发送 Cookie | 发送 Cookie |
预加载 | <link rel="prerender" href="..."/> | 发送 Cookie | 发送 Cookie |
GET 表单 | <form method="GET" action="..."> | 发送 Cookie | 发送 Cookie |
POST 表单 | <form method="POST" action="..."> | 发送 Cookie | 不发送 |
iframe | <iframe src="..."></iframe> | 发送 Cookie | 不发送 |
AJAX | $.get("...") | 发送 Cookie | 不发送 |
Image | <img src="..."> | 发送 Cookie | 不发送 |
None
无论是否跨站都会发送cookie
csrf攻击
csrf全称是:Cross-site request forgery
,意思为跨站点伪造攻击。原理是借助用户已有的身份标志,去完成攻击操作。例如用户在某系统登录成功后,进入到了另外的攻击网站,网站后台不经过用户允许发起删除数据、篡改数据的操作(由于已经登录成功,会携带cookie身份标志
)。防御这类攻击的方案有多种:
1.阻止cookie身份标志在未经允许的情况下被发送,可以借助samesite
属性实现
2.由于攻击请求都是来源于攻击网站,服务端可以通过referer
头来验证请求方的身份
3.csrftoken
,csrf攻击的要点就是用户身份可以伪造,所以我们可以在请求中加入一些自己的标志,由服务端为客户端生成专用的token,在发送请求时添加到请求头中,攻击网站发起的恶意攻击则不能伪造出这样的标志
和localStorage的比较
跟cookie
相比较,localStorage
的优势是存储空间更大,而在安全性方面,反而不如cookie
,对于xss攻击,cookie
和localStorage
都可以被读取,但cookie
可以设置httpOnly
属性,localStorage
没有任何的防御机制。
和session的比较
session
是被存储在服务端的,也就是服务器的内存中,相对cookie
,使用session存储重要信息更安全,但是也有缺点,会消耗服务器内存,同时session在多台服务器的同步也是一个问题。