很多技术博客讲到 session,cookie 和 token 的区别和联系 ,但是介绍的不够清晰,因此参考了一些博客,在这里总结记录一下。
众所周知,HTTP 是一种无状态协议,即每次客户端发送请求时,对于服务端来说接收到的都是一个全新的请求,因此服务器并不知道客户端的历史请求记录。
比如不同的用户登录退出一个网站,每个人的会话状态都是不同的,所以网站需要对这些会话进行管理,而我们今天要讨论的 cookie,session, token 就是用来管理会话的手段。
1. cookie
cookie 是什么
cookie 是浏览器里面能永久存储的一种数据,是浏览器实现的一种数据存储功能。
cookie 有什么用
因为 HTTP 协议是无状态的,服务器无法记录用户上一次的操作,会造成交互上的阻碍。而 cookie 则可以做到绕开 HTTP 的无状态,也就是服务器可以从 cookie 中读取包含的信息,来维护用户和服务器会话中的状态(比如购物 / 登录)。
cookie 有什么特点
-
cookie 存储在客户端:cookie是由服务器生成后发送到客户端的,客户端以 key-value 形式将数据保存在本地,在下次请求同一网站时会把该 cookie 发送给服务端。
-
cookie为不可跨域的:每个 cookie 都会绑定单一的域名,无法在别的域名下获取和使用,不过一级域名和二级域名之间是允许共享使用的。
cookie 中的参数说明
参数 | 说明 | 后端调用 |
---|---|---|
Domain | 指定 cookie 所属域名,默认是当前域名 | cookie.setDomain("") |
Max-Age | 设置cookie的过期时间,单位为秒 | cookie.setMaxAge(10) |
Path | 指定 cookie 在哪个路径(路由)下生效,默认是 ‘/’ | cookie.setPath("/") |
HttpOnly | 如果给某个 cookie 设置了 httpOnly 属性,则无法通过 JS 脚本读取到该 cookie 的信息,但还是能通过 Application 中手动修改 cookie,所以只是一定程度上可以防止 XSS 攻击,不是绝对的安全 | cookie.setHttpOnly(true) |
Secure | 告诉浏览器此 cookie 只能在 HTTPS 安全协议中传输,如果是 HTTP 则禁止传输 | cookie.setSecure(true) |
cookie 的局限性
-
cookie 必须在 HTML 文件的内容输出前进行设置;
-
不同的浏览器对 cookie 的处理不一致,使用时一定要注意;
-
客户端用户如果设置禁用 cookie,则 cookie 不能建立;
-
每个客户端浏览器可创建的 cookie 数量最多为 300 个,并且每个不能超过 4KB,每个 Web 站点能设置的 cookie 总数不能超过 20 个;
HTTP 的传输有一个很大的问题,就是明文传输。那么,明文传输会导致什么问题呢?
意味着我可以抓包来获取用户信息(比如使用 WireShark \ Fiddle 等工具),而且 HTTP 请求是可以篡改的,且篡改难度很低。同时,根据客户端信息不可靠原则,我们需要一个东西来验证用户的身份,此时就轮到 session 出场了。
2. session
session 是什么
session 是一种抽象的概念,开发者为了实现中断和继续等操作,将 user agent 和 server 之间一对一的交互抽象为 “会话”,进而衍生出 “会话状态”。
session 有什么用
服务端为每个用户生成不同的身份标识 session id,还有与之相对应的信息,比如用户 id 和登录时间等。通过服务端的 session 和浏览器的cookie 一一对应,来区分用户身份。
session 有什么特点
- cookie 是一个实际存在的东西,是 http 协议中定义在 header 中的字段,而 session 只是一种 cookie 的后端无状态实现;
- session 是基于 cookie 实现的,它存储在服务器端,可以理解为一个状态列表,拥有一个唯一识别符号 sessionId,通常存放于 cookie 中;
- 移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token;
session 的工作流程
浏览器访问服务器的流程如下:
-
浏览器发送一个 http 请求到服务器端。
-
服务端接收请求后,创建对应的 session ,并发送一个 http 响应到客户端,这个响应的响应头中包含了 sessionId;
-
浏览器接收到服务端返回的 sessionId 后,将此信息存入 cookie ,同时 cookie 记录此 sessionId 属于哪个域名;
-
当用户第二次发起请求时,请求会自动判断此域名下是否存在 cookie 信息,如果存在,浏览器会自动在请求头中添加 cookie 并发送到服务端;
-
服务端接收请求,会从 cookie 中获取 sessionId,再根据 sessionId 查找对应的 session 信息,如果没有找到,则说明用户没有登录或者登录失效;如果找到了,则证明用户已经登录,可继续执行后面的操作。
3. token
token 是什么
token 的意思是 “令牌” ,是用户身份的验证方式,简单的 token 组成为:uid (用户唯一的身份标识)、time (当前时间的时间戳)、sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串),相当于上文提到的 session id。
token 有什么用
token 的用户认证是一种服务端无状态的认证方式,所以用解析 token 的计算时间可以换取 session 的存储空间,从而来减轻服务器的压力,减少对数据库的频繁查询。
同时,token 可以抵抗 csrf,具有更高的安全性。
token 有什么特点
- cookie + session 不能抵抗 csrf,但是 token 可以,因为浏览器不会自动把 token 添加到headers 里,攻击者也无法访问用户的 token,所以提交的表单无法通过服务器过滤,也就无法形成攻击;
- token 的认证方式类似于临时的证书签名, 并且是一种服务端无状态的认证方式, 所谓无状态就是服务端并不会保存身份认证相关的数据,非常适合于 REST API 的场景。
- cookie 和 session 有自动过期的设置,而 token 的状态和过期时间需要自己手动设置。比如说,token中存储用户登录的时间,服务端每次收到请求后,都需要去验证这个时间是否过期。
token 认证流程
- 客户端使用用户名和密码请求登录
- 服务端收到请求,去验证用户名与密码
- 验证成功后,服务端签发一个 token ,并把它发送给客户端
- 客户端接收 token 以后会把它存储起来,比如放在 cookie 里或者 localStorage 里
- 客户端每次发送请求时都需要带着服务端签发的 token(把 token 放到 HTTP 的 Header 里)
- 服务端收到请求后,需要验证请求里的 token ,如验证成功则返回对应的数据
欢迎关注我的公众号,用讲故事的方式学技术。
这里有脑洞大开的奇葩故事,也有温暖文艺的心灵感悟。
技术知识,也可以很有趣。