Cookie、Session、Token 笔记

527 阅读8分钟

Cookie

Cookie 在计算机中是个存储在浏览器目录中的文本文件,当浏览器运行时,存储在 RAM 中发挥作用(此种 Cookies 称作 Session Cookies),一旦用户从该网站或服务器推出,Cookie 可存储在用户本地的硬盘上(此种 Cookies 称作 Persistent Cookies)。

  • 时效性:

    • 分类:持久化 Cookie、非持久化 Cookie

      • 非持久化 Cookie 存储在内存中,即生命周期基本和 app 保持一致,app 关闭后,Cookie 丢失。
      • 持久化 Cookie 存储在本地磁盘中,app 关闭后不丢失。
    • 如果我们要使用 Cookie 的持久化策略,思想上可以参考非持久化策略,只需修改存储方式:

      A:通过响应拦截器从 response 取出 cookie 并保存到本地,通过请求拦截器从本地取出 cookie 并添加到请求中。

      B:自定义 CookieJar,在 saveFromResponse() 中保存 cookie 到本地,在 loadForRequest() 从本地取出 cookie。

  • 使用限制:Cookie 必须在 HTML 文件的内容输出之前设置,不同的浏览器对 Cookie 的处理不一致,客户端用户如果设置禁止 Cookie,则 Cookie 不能建立。并且在客户端,一个浏览器能创建的 Cookie 数量最多为300个,并且每个不能超过 4KB,每个 Web 站点能设置的 Cookie总数不能超过 20 个。

  • 执行流程:

    A:客户端会发送一个 http 请求到服务器端。

    B:服务器端接收客户端请求后,发送一个 http 响应到客户端,这个响应头,其中就包含 Set-Cookie 头部。

    C:在客户端发起的第二次请求(如果服务器需要我们带上 Cookie,我们就需要在 B 步骤上面拿到这个 Cookie 然后作为请求头一起发送第二次请求),提供了服务器端可以用来唯一标识客户端身份的信息。这时,服务器端也就可以判断客户端是否启用了 cookies。尽管,用户可能在和应用程序交互的过程中突然禁止 cookies 的使用,但是,这个情况基本是不太可能发生的,所以可以不加以考虑。

    img

Session

Session 是对于服务端来说的。Session 是服务器在和客户端建立连接时添加客户端连接标志,最终会在服务器(Apache、Tomcat、JBoss)转化为一个临时 Cookie 发送给客户端,当客户端第一请求时服务器会检查是否携带了这个 Session(临时 Cookie),如果没有则会添加 Session,如果有就拿出这个 Session 来做相关操作。

  • session 产生的必要性:cookie 是存在客户端,而且其本身存储的尺寸大小有限,最关键的是用户可以是可见的,并可以随意地修改,很不安全。

Token

Token 是用户身份的验证方式,又称为令牌。

  • 最简单的 token 组成:

    • 用户唯一的身份标识 uid
    • 当前时间的时间戳 time
    • 签名 sign:token 的前几位 + 盐以哈希算法压缩成一定长的十六进制字符串
      • 目的:防止恶意第三方拼接 token 请求服务器。
    • (不变的参数)
      • 目的:避免多次查库。
  • 应用场景:

    • 用户首次登录 / 注册之后,服务器端生成一个 token 值,这个值,会在服务器保存 token 值(保存在数据库中),再将这个 token 值返回给客户端。

    • 客户端拿到 token 值之后,进行本地保存。

    • 当客户端再次发送网络请求(一般不是登录请求)的时候,就会将这个 token 值附带到参数中发送给服务器。

    • 服务器接收到客户端的请求之后,会取出 token 值与保存在本地(数据库)中的 token 值做对比。

      • 情况1:两个 token 值相同,说明用户登录成功过,当前用户处于登录状态。

      • 情况2:没有这个 token 值,说明没有登录成功。

      • 情况3:两个 token 值不同,说明原来的登录信息已经失效,让用户重新登录。

Cookie 和 Session 的区别

  • Cookie 保存在浏览器中,以键值对的形式存在,可以用来做用户认证,存储上限一般为 4K;由于数据存储在浏览器中,容易被其它恶意程序利用,数据的安全性不高。
  • Session 将用户的会话信息保存在服务器端,key 值是随机产生的字符串,value 值是 session 的内容,依赖于 cookie 将每个用户对应的 key 值保存到浏览器中,session 没有具体的大小限制,可以存储的数据量比 cookie 大;由于信息保存在服务器端,不会轻易地被恶意程序利用,数据的安全性相对较高。

Token 和 Session 的区别

  • 作为身份认证,token 安全性比 session 好,因为每个请求都有签名还能防止监听以及重放攻击,而 session 就必须靠链路层来保障通讯安全了。

  • Session 是一种 HTTP 存储机制,目的是为无状态的 HTTP 提供持久机制。所谓 Session 认证只是简单地把 User 信息存储到 Session 里,因为 SID 的不可预测性,暂且认为是安全的,这是一种认证手段。

  • 而 Token,如果指的是 OAuth Token 或类似的机制的话,提供的是认证和授权 ,认证是针对用户,授权是针对App。其目的是让某 App 有权利访问某用户的信息。这里的 Token 是唯一的,不可以转移到其它 App 上,也不可以转到其它用户上。

  • 简单来说,如果你的用户数据可能需要和第三方共享,或者允许第三方调用 API 接口,用 Token。如果永远只是自己的网站,自己的 App,用什么就无所谓了。

  • token 就是令牌,比如你授权(登录)一个程序时,他就是个依据,判断你是否已经授权该软件;cookie 就是写在客户端的一个 txt 文件,里面包括你登录信息之类的,这样你下次在登录某个网站,就会自动调用 cookie 自动登录用户名;session 和 cookie 差不多,只是 session 是写在服务器端的文件,也需要在客户端写入 cookie 文件,但是文件里是你的浏览器编号。Session 的状态是存储在服务器端,客户端只有session id;而 Token 的状态是存储在客户端。

Session 的安全性

Session 不安全的根本原因

  • 会话传递机制导致的(Cookie 和 URL 参数)劫持问题。只要有网络就会有劫持。
  • 会话固定。

Session 的数据是存储在服务器端的,那么服务器如何保持会话呢? 或者说如何找到特定的用户呢?

两种方式:Cookie 和 URL 参数来传递。

一涉及到传递就会有危险,并且在 PHP 中这个危险被放大了。

仅仅使用 Cookie 来存放 Session ID

Session ID 可以使用 Cookie 和 URL 参数来传递,相对来说,Cookie 更安全,URL 暴露的频率更高,假如不考虑 Cookie 被禁用的问题,应该只使用 Cookie 来传递。PHP.ini 提供了 session.use_only_cookies 指令来加强安全性。

保护你的 Cookie

Cookie 本身也是不安全的,所以提升 Cookie 安全性的方法也同样适用于 Session。关键就是 HttpOnly(不允许 JavaScript 脚本读取),另外假如网站是支持 Https 协议的,那么配置 Cookie 只能通过 Https 协议传递。

Cookie 和 Session 的过期时间保持一致

  • Session 的存活时间是变化的,只要会话一初始化,Session 文件的修改时间就会更新。换句话说,设置该 GC 时间为 2 小时过期,但是只要用户间隔 2 小时一直保持会话更新(比如刷新页面),则 Session 一直会存在。
  • GC 到期后,由 PHP 来控制删除 Session 文件,但是并不是每次就会删除过期文件,所以不能依赖它,但是可以通过自定义 Session 管理器来实现这个机制。

考虑到 Session GC 不可依赖,所以可以间接设置 Cookie 对应的过期时间(session.cookie_lifetime 指令)等于 GC 时间,这样一到过期时间,由于 Cookie 失效了,等同于 Session 也失效了(虽然 Session 对应的文件并没有删除,假如攻击者知道 Session ID 还是会带来安全问题)。

Regenerate the Session ID

假如攻击者劫持了你的 Session ID,但是你又不知道,为了安全建议经常性的重置 Session ID(比如不定期的使用 session_regenerate_id()函数),这样攻击者等同于拿到的是旧的 Session ID(假设新的 Session ID 攻击者获取不到),这样就不能获取 Session 数据了。但这也不是完全有效的(因为攻击者有方法能劫持你的 Session ID)。

更有效的方式应该是在用户操作更高权限功能的时候(比如电商结账的时候),让用户重新输入密码去验证(获取用户密码是另外一种攻击方式)。这是从应用层角度考虑最有效的保护方式。

会话固定

两层意思:

  • 只要有正确的 Session ID,不管你从什么设备上发起请求,服务器程序校验出有对应的 Session 信息就认为是正确的。

  • 假如客户端伪造一个 Session ID,PHP 处理的时候看到这个 Session ID 不存在,就以这个 Session ID 去初始化,这样的机制可能带来攻击。

    • 伪造包含两部分:

      • 本身服务器上没有这个 Session ID

      • Session ID 的值的格式也可以是错误的

正确的关闭会话方式

关闭会话包含三个方面:

  • 传递 Session ID 的 Cookie 应该删除
  • Session 文件应该删除
  • 在 PHP 进程中的 Session 全局变量也应该清除

资料来源于

www.jianshu.com/p/bd1be47a1…

juejin.cn/post/684490…

www.jianshu.com/p/c4b32eb24…