为什么Token存在Cookie里,却比Cookie本身更安全?

37 阅读3分钟

疑问:

使用Token(如JWT)进行身份验证比使用Cookie更安全,尤其是可以防止CSRF攻击。但有趣的是,很多实际应用中,Token仍然存储在Cookie中。这就引出了一个看似矛盾的问题:为什么Token存在Cookie里,却比Cookie本身更安全?

1. 背景:传统Cookie身份验证与Token身份验证

在传统的Web应用中,服务器使用Session和Cookie来管理用户状态。流程通常如下:

  1. 用户登录,服务器创建Session,将Session ID通过Cookie返回给浏览器。
  2. 浏览器在后续请求中自动携带这个Cookie(包含Session ID)。
  3. 服务器根据Session ID查找Session,验证用户身份。

这种方式的优点是简单,浏览器自动处理Cookie,开发者无需额外编码。但缺点也很明显:CSRF攻击、难以跨域、服务器需要存储Session等。

而Token身份验证(如JWT)的流程不同:

  1. 用户登录,服务器生成一个Token(包含用户信息等),返回给客户端(可以存储在Cookie、localStorage等)。
  2. 客户端在后续请求中需要显式地携带这个Token(通常在Authorization头中)。
  3. 服务器验证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