Token的安全存储与传输

Token是什么

究竟什么才算是Token,我一直没有找到比较好的定义,但是回过头来看一下它的翻译,才明白,原来名字就是定义了,Token就是令牌。

那么什么是令牌呢?

先看一下我们现实生活中的令牌。

https://res.cloudinary.com/dvtfhjxi4/image/upload/v1587640464/图片1_pntvdk.jpg

为什么它是个令牌呢?因为六扇门可以验证其真实性,同时六扇门可以从中获取持有该令牌的人的身份。

从这里我们就可以给Token下一个大致的定义:

  • 可以被某个服务认证其真实性。

  • 该服务可以从中获取用户的信息。

也就是说SessionID是Token,JWT也是Token。

基于Token的认证流程

https://res.cloudinary.com/dvtfhjxi4/image/upload/v1587640876/computer_network/图片1_m5icmc.png

大致就分为几步:

  • 用户发送登陆请求到服务器,携带用户名和密码登陆。
  • 服务器收到请求后验证其正确性,如果认证成功,就返回一个Token给前端
  • 前端收到Token之后存储下来,接下来每个请求都带上Token
  • 服务器从请求中拿出Token,验证其有效性以及对应的用户信息或者权限等,如果认为可以发起这个请求再进行处理。

这几个步骤看起来很简单,但是可以有很多的升级版,比如

  • 第一步的登陆用OAuth协议去做,那就是我们常见的第三方登陆,如果对OAuth有疑惑的可以看一下OAuth协议设计

  • 第二步如果选择将信息存储在服务器Session,并返回一个SessionID,那么Token就是SessionID,如果服务器不进行任何存储,而是选择将部分用户信息加密签名丢回给前端,那就可以用JWT。

  • 第三步中Token的存储有很多方案,比如Cookie,LocalStorage,SessionStorage等,甚至是USB Token,从安全,性能,成本等方面考虑这些方案的优缺点是什么。

  • 还有虽然我们可以通过签名的方式保证Token的不可篡改,但是整个过程中如何保证我们的Token不被窃听?

除此之外,我们还可以考虑一下为什么第二步有时候返回两个token,如果看了上面提到的OAuth协议设计应该对这个问题会有答案。

Token的几个存储方案比较

cookie是大家最熟悉的前端存储方案。大家对它的一些特性很熟悉,比如同源限制,自动携带等等。那这里就主要说它的几个安全方面的配置:

  • http-only:这个参数限定只能通过请求自动携带的方式获取cookie,没办法通过脚本去获取,这样一来就可以有效避免cookie被xss攻击,及时你的页面被不小心注入脚本,也无法获取你的cookie。
  • same-site:这个属性规定,只有请求是从同源页面发起才能获取cookie。这个主要是用来防御csrf的,因为如果只要是同源请求就可以自由携带cookie的话,很容易就遭受csrf攻击,比如在token失效之前打开了攻击者页面,该页面自动向后台发送请求,就会携带cookie。
  • secure:这个参数可以让cookie只会被https请求携带,https应该是是目前最好用的几种防止中间人攻击的方式之一,可以有效防止你的token被窃听。

其他前端存储方案

SessionStorage:sessionStorage 特别的一点在于,即便是相同域名下的两个页面,只要它们不在同一个浏览器窗口中打开,那么它们的 sessionStorage 内容便无法共享;

LocalStorage:在同源的所有标签页和窗口之间共享数据,保存的数据长期存在,下一次访问该网站的时候,网页可以直接读取以前保存的数据。

IndexDB:类似LocalStorage,只不过容量大很多

硬件级别的Token保护:USB Token

将Token存储在独立的硬件上,重要请求需要用户自主填写Token。

USB Key中也可以存储数字证书,这个最常见的应该就是网银的U盾了。

比较

SessionStorage安全性较高,能比较好防御CSRF,但是对XSS无用,且局限较大。

LocalStorage和IndexDB受同源保护,但是一旦被注入脚本也很危险。

USB Key安全性较高,属于物理级别的防御,但是有一定的成本。

Cookie最方便,但是默认状态下最不安全,需要将http-only,same-site,secure等开启才能有较高的安全性。

Token的安全传输与HTTPS

准确地讲HTTPS是协议栈。

最上层是HTTP,接着是SSL/TLS,接着是TCP。

HTTP的数据包在进入TCP发送缓存之前被SSL/TLS加密就叫做HTTPS。

所以想要搞明白HTTPS,就要搞明白HTTP。而HTTP协议本身并不复杂,它的复杂体现在各种header上,这些header都是 一些应用上的设计,所以这一层叫应用层。

想要搞懂HTTP,最好是搞懂TCP。

我整理了几篇关于TCP和HTTPS的博客,它们是我在学习是一些疑惑的解答。

在看的时候如果带着我的这些问题可能会更好:

  • HTTP协议是什么?用于获取万维网服务器资源的协议,基于TCP,熟知端口是80 。

  • TCP协议是什么?传输层可靠传输协议,缓存上层协议不断发送的数据然后打包发送给不可靠的IP协议,通过一系列措施进行可靠传输,流量控制和拥塞控制,最重要的是面向连接的特性,这也是加密数据不会混淆的重要基础。

  • SSL/TLS如何加密数据?用对称秘钥。

  • 对称秘钥如何生成?为什么不用非对称?对称秘钥就是每次TCP握手阶段用非对称秘钥生成的。

  • 如何保证公钥的真实性?证书。

  • 如何验证证书的有效性?根证书,证书链。

这里是链接地址:

TCP详解

HTTPS详解