前言
众所周知,http 协议本身是无状态的,而前后端交互最普遍的场景则是鉴权。cookie 的存在也是与我们的鉴权工作有关系,如今的鉴权方式一般都是使用JWT (JSON WEB TOKEN),前端在登录后得到 token 放入请求头的 Authorization 字段中,后续请求也携带上这个请求头来完成鉴权工作,而 cookie 的使用场景也在逐步减少,但是我们还是需要好好的了解一下这位身经百战的老将。或许你们在面试的时候也有碰到过这样的问题:请问,用cookie来鉴权和在请求头上带token的鉴权方式有什么区别呢?。想必你应该也了解过这类的问题,那接下来我们话不多说就再来一起了解一下 cookie 这位 “老伙伴” 吧!
Cookie
首先我们先来了解一下 cookie 的几个属性
| 属性 | 含义 |
|---|---|
| Name/Value | 设置Cookie的名称及相对应的值,对于认证Cookie,Value值包括Web服务器所提供的访问令牌。 |
| Expires | 设置Cookie的生存期。有两种存储类型的Cookie:会话性与持久性。Expires属性缺省时,为会话性Cookie。 |
| Path | 定义了Web站点上可以访问该Cookie的目录 |
| Domain | 指定了可以访问该 Cookie 的 Web 站点或域。Cookie 机制并未遵循严格的同源策略,允许一个子域可以设置或获取其父域的 Cookie。 |
| Secure | 指定是否使用HTTPS安全协议发送Cookie。使用HTTPS安全协议,可以保护Cookie在浏览器和Web服务器间的传输过程中不被窃取和篡改。 |
| HTTPOnly | 用于防止客户端脚本通过document.cookie属性访问Cookie,有助于保护Cookie不被跨站脚本攻击窃取或篡改。 |
以上来自百度百科-有删减
以上这些属性构成了我们的 cookie。
接下来我们来简述一下 cookie 的机制流程。以掘金为例,当我们进行登陆,发送一个 HttpRequest 到服务器,服务器校验成功后发送一个 HttpResponse 响应到客户端,其中包含 Set-Cookie 的头部,客户端保存 cookie,之后再次向服务器发送请求时,HttpRequest 请求中会包含一个 cookie 的头部来完成鉴权操作。
如图,我们登陆完成后再次访问 juejin.cn 我们之前登陆的 cookie 就会携带在请求头上,来完成鉴权登陆。
而鉴权一般都需要对安全性有高的要求,所以以 sessionid 为例。都必须带上 Secure 属性以及 HTTPOnly。防止客户端通过脚本的方式进行窃取或篡改。
而且 cookie 是不可跨域的,隐私安全机制禁止网站非法获取其他网站的Cookie,通常情况下同一个一级域名下的子域名也不可以互用 cookie。虽然如此,但如上文所介绍的一样,cookie 机制并未遵循严格的同源策略,允许一个子域可以设置或获取其父域的 cookie。而我们经常会碰到单点登陆的需求,如果需要基于 cookie 呢,就需要设置 Domain 属性,这样子子域名就可以获取其一级域名下的所有 cookie。 比如,如果 aa.juejin.cn 在通常情况下 bb.juejin.cn 的域名是不共享的。但是设置了其 cookie 的 Domain 属性为 .juejin.cn 后,它们的 cookie 就可以进行共享。就可以实现在 login.juejin.cn 上登陆后,*.juejin.cn 都不需要登陆。(以上场景均为假设)
以上为简单流程图
还有其他未涉及到的属性如 Name/Value、Path、Expires如表格里如述这里就不再赘述了。
请问,用cookie来鉴权和在请求头上带token的鉴权方式有什么区别呢?
通过以上介绍,想必大家对 cookie 已经有所认知了。那我们就回归到开头的问题。
请问,用cookie来鉴权和在请求头上带token的鉴权方式有什么区别呢?
首先呢。我们基于 cookie 来实现鉴权的方式呢。通常不会直接把我们的鉴权信息直接暴露在 cookie 里头,这样做的安全性可靠性都大大降低,十分容易受到攻击。而且cookie是一小段文本信息,伴随着用户请求在 Web 服务器和浏览器之间传递,其大小限制在4k左右(不同浏览器略有不同),这样的限制使其极其不便于拓展。
所以大部分的 cookie 鉴权方式采用服务端记录我们每次鉴权完成所生产的 sessionid (可以通过上图看到)。通过这个 id 呢,服务端可以找到这个用户的一些基本信息,以完成鉴权。通过这种方式呢,也暴露出一些问题,当每次请求鉴权完成。服务端都需要去记录这个 session 以便后续的鉴权工作,那当用户越来越多,那服务端需要记录的 session 也会也来越多,内存的开销也会不断增加。
以及 CORS(跨域资源共享), 当我们需要让数据跨多台移动设备上使用时,跨域资源的共享会是一个让人头疼的问题。在使用 Ajax 抓取另一个域的资源,就可以会出现禁止请求的情况。
CSRF(跨站请求伪造),用户在访问银行网站时,他们很容易受到跨站请求伪造的攻击,并且能够被利用其访问其他的网站。
还有就是 cookie 是可以通过用户在浏览器中设置为禁止,那么鉴权工作将无法完成。
而 Token 呢?主要有以下几点:
-
无状态 在客户端存储的
token是无状态的。基于这种无状态和不存储Session信息,负载负载均衡器能够将用户信息从一个服务传到其他服务器上。客户端只需要将服务端签发的token在每次发送请求的时候附在请求头中即可。 -
安全性 请求中使用
token而是cookie能够防止CSRF(跨站请求伪造)。而且通常伴随着token有效时间,需要客户端在一段时间内就进行token的刷新,增加token得安全性、可靠性。 -
可扩展性
token 能够创建与其它程序共享权限的程序。例如,能将一个随便的社交帐号和自己的大号(Fackbook或是Twitter)联系起来。当通过服务登录Twitter(我们将这个过程Buffer)时,我们可以将这些Buffer附到Twitter的数据流上(we are allowing Buffer to post to our Twitter stream)。
使用 token 时,可以提供可选的权限给第三方应用程序。当用户想让另一个应用程序访问它们的数据,我们可以通过建立自己的API,得出特殊权限的 token。
- 多平台跨域
CORS(跨域资源共享) ,对应用程序和服务进行扩展的时候,需要介入各种各种的设备和应用程序。
Having our API just serve data, we can also make the design choice to serve assets from a CDN. This eliminates the issues that CORS brings up after we set a quick header configuration for our application.
只要用户有一个通过了验证的token,数据和资源就能够在任何域上被请求到。
- 基于标准
结束
之所以写这篇文章呢,是因为最近参与开发了一个使用 cookie 进行鉴权得方式。之前对 cookie 得了解少之又少。刚好这次让自己补习了一下这一块所欠缺得知识。如果文章内容有错误还希望大佬们帮忙指出,谢谢!