疑问:
使用Token(如JWT)进行身份验证比使用Cookie更安全,尤其是可以防止CSRF攻击。但有趣的是,很多实际应用中,Token仍然存储在Cookie中。这就引出了一个看似矛盾的问题:为什么Token存在Cookie里,却比Cookie本身更安全?
1. 背景:传统Cookie身份验证与Token身份验证
在传统的Web应用中,服务器使用Session和Cookie来管理用户状态。流程通常如下:
- 用户登录,服务器创建Session,将Session ID通过Cookie返回给浏览器。
- 浏览器在后续请求中自动携带这个Cookie(包含Session ID)。
- 服务器根据Session ID查找Session,验证用户身份。
这种方式的优点是简单,浏览器自动处理Cookie,开发者无需额外编码。但缺点也很明显:CSRF攻击、难以跨域、服务器需要存储Session等。
而Token身份验证(如JWT)的流程不同:
- 用户登录,服务器生成一个Token(包含用户信息等),返回给客户端(可以存储在Cookie、localStorage等)。
- 客户端在后续请求中需要显式地携带这个Token(通常在Authorization头中)。
- 服务器验证Token的有效性,并从中提取用户信息。
这种方式是无状态的,服务器不需要存储Token,可以轻松实现跨域,并且更易于防御CSRF攻击。
2. 为什么Cookie容易受到CSRF攻击?
CSRF(Cross-Site Request Forgery)攻击的原理是:攻击者诱导用户访问一个恶意网站,该网站自动向目标网站(用户已登录)发起请求。由于浏览器会自动携带目标网站的Cookie,所以服务器会认为这是用户的正常请求,从而执行攻击者期望的操作。
关键点在于:浏览器会自动在请求中携带Cookie,而用户和服务器可能完全不知情。
3. 为什么Token(即使存储在Cookie中)可以防御CSRF?
这里有一个重要的区别:即使Token存储在Cookie中,我们也可以通过一些方式让它不被浏览器自动利用。
常见的做法是:
- 将Token存储在Cookie中,但是前端代码不直接依赖这个Cookie进行身份验证。
- 前端通过JavaScript从Cookie中读取Token,然后在请求时将其放入Authorization头中。
- 服务器端验证Authorization头中的Token,而不是Cookie中的Token。
这样,即使恶意网站诱导用户发起请求,请求的Cookie中虽然包含了Token,但是恶意网站无法读取这个Token(因为同源策略),也无法在跨域请求中设置Authorization头(因为CORS限制)。因此,服务器不会认为这个请求是合法的。
但是,请注意,如果Token仅仅存储在Cookie中,并且服务器仍然从Cookie中读取Token进行验证,那么它仍然和传统的Session Cookie一样容易受到CSRF攻击。
所以,关键点在于:服务器不依赖自动携带的Cookie进行身份验证,而是依赖前端显式传递的Token(在请求头中) 。
总结: 自定义token有什么优势
- 可以防止csrf攻击
- 实现无状态api,不需要依赖服务器存储的session
- 接口更加通用,在某些客户端发起的请求会没带cookie字段
- 显示传输更加清晰直观
cookie的属性有哪些呢
- 以键值对形式存储key value
- domain
- path
- secure
- httponly
- samesite