会话管理之Session、cookie、token
HTTP是无状态的,每次请求都是一个新的HTTP协议,就是请求加响应,不知道是谁刚刚发了HTTP请求,每个请求都是全新的。但是随着交互式Web应用的兴起,像在线购物网站,需要登录的网站等等,马上就面临一个问题,那就是要管理会话,必须记住哪些人登录系统, 哪些人往自己的购物车中放商品,也就是说必须把每个人区分开。
一、 session
为解决上面的问题,想出的办法就是给大家发一个会话标识(session id),就是一个随机的字串,每个人收到的都不一样, 每次大家向服务器发HTTP请求的时候,把这个字符串给一并捎过来, 这样就能区分开谁是谁了。
session存在于服务器中,可以存放用户的状态信息,客户端发送请求时,服务器会生成一个session对象,session对象生成一个对应的sessionID返回给客户端,客户端再次请求时会在cookie中携带该sessionID随请求一起发送给服务器,服务器对sessionID进行验证是否有效。

二、 Cookie
cookie 是一个非常具体的东西,指的就是浏览器里面能永久存储的一种数据,仅仅是浏览器实现的一种数据存储功能。
cookie由服务器生成,发送给浏览器,浏览器把cookie以kv形式保存到某个目录下的文本文件内,下一次请求同一网站时会把该cookie发送给服务器。由于cookie是存在客户端上的,所以浏览器加入了一些限制确保cookie不会被恶意使用,同时不会占据太多磁盘空间,所以每个域的cookie数量是有限的。
三、 token
如上所述,服务器要保存所有人的session id,如果访问服务器多了,就得由成千上万,甚至几十万个。这对服务器来说是一个巨大的开销 ,严重的限制了服务器扩展能力,比如说用两个机器组成了一个集群,小F通过机器A登录了系统,那session id会保存在机器A上,假设小F的下一次请求被转发到机器B怎么办?机器B并没有小F的 session id。于是有人就一直在思考, 为什么要保存这可恶的session呢,只让每个客户端去保存该多好?
可是如果不保存这些session id , 怎么验证客户端发给的session id 的确是服务器生成的呢? 如果不去验证,我们都不知道他们是不是合法登录的用户,那些不怀好意的家伙们就可以伪造session id ,为所欲为了。
关键点就是验证。
比如说,小F已经登录了系统,我给他发一个令牌(token),里边包含了小F的 user id,下一次小F 再次通过Http 请求访问我的时候,把这个token 通过Http header 带过来不就可以了。
不过这和session id没有本质区别啊,任何人都可以可以伪造,所以我得想点儿办法,让别人伪造不了。
那就对数据做一个签名吧,比如说我用HMAC-SHA256 算法,加上一个只有我才知道的密钥,对数据做一个签名,把这个签名和数据一起作为token ,由于密钥别人不知道,就无法伪造token了。

这个token 服务器不保存, 当小F把这个token 给服务器发过来的时候,服务器再用同样的HMAC-SHA256 算法和同样的密钥,对数据再计算一次签名, 和token 中的签名做个比较,如果相同,就知道小F已经登录过了,并且可以直接取到小F的user id ,如果不相同,数据部分肯定被人篡改过,就告诉发送者:对不起,没有认证。

这样一来,服务器就不保存session id 了,只是生成token , 然后验证token ,节省了存储空间 !
Tokens的优势
1、无状态、可扩展
在客户端存储的Tokens是无状态的,并且能够被扩展。基于这种无状态和不存储Session信息,负载均衡器能够将用户信息从一个服务传到其他服务器上。
如果我们将已验证的用户的信息保存在Session中,则每次请求都需要用户向已验证的服务器发送验证信息(称为Session亲和性)。用户量大时,可能会造成一些拥堵。
但是不要着急。使用tokens之后这些问题都迎刃而解,因为tokens自己hold住了用户的验证信息。
2、安全性
请求中发送token而不再是发送cookie能够防止CSRF(跨站请求伪造)。即使在客户端使用cookie存储token,cookie也仅仅是一个存储机制而不是用于认证。不将信息存储在Session中,让我们少了对session操作。
token是有时效的,一段时间之后用户需要重新验证。我们也不一定需要等到token自动失效,token有撤回的操作,通过token revocataion可以使一个特定的token或是一组有相同认证的token无效。
3、可扩展性
Tokens能够创建与其它程序共享权限的程序。例如,能将一个随便的网站帐号和自己的微信号联系起来,用微信账号登录该网站。使用tokens时,可以提供可选的权限给第三方应用程序。当用户想让另一个应用程序访问它们的数据,我们可以通过建立自己的API,得出特殊权限的tokens。
4、多平台跨域
我们提前先来谈论一下CORS(跨域资源共享),对应用程序和服务进行扩展的时候,需要介入各种各种的设备和应用程序。
只要用户有一个通过了验证的token,数据和资源就能够在任何域上被请求到。Access-Control-Allow-Origin: *
5、基于标准
创建token的时候,你可以设定一些选项。但是标准的用法会在JSON Web Tokens体现。
最近的程序和文档是供给JSON Web Tokens的。它支持众多的语言。这意味在未来的使用中你可以真正的转换你的认证机制。
四、 会话管理类漏洞
1、 会话劫持
就是通过获取用户sessionid,使用sessionid登录目标账号的攻击办法。

如何获取Cookie:
暴力破解:尝试各种Sessionid,直到破解为止;
预测:如果Sessionid使用非随机的方式产生,就有可能计算出来;
窃取:XSS攻击、使用网络嗅探(中间人攻击)等方法获得。


防御方法:
(1) XSS漏洞引起的会话劫持:
可以使用http-only来防止js获取cookie中的sessionid信息。Http-only这个参数的优点是不会被js获取。
(2) 中间人攻击引起的会话劫持
可以使用HTTP-SSL+secure来保证sessionid不被获取。Secure属性如果为true时,此cookie只有在Https协议中才会进行传输。
2、 会话固定
会话固定是一种诱骗受害者使用攻击者指定的会话标识的攻击手段。这是攻击者获取合法会话标识的最简单的办法。会话固定也可以看成是会话劫持的一种类型,原因是会话固定的攻击的主要目的同样是获得目标用户的合法会话,不过会话固定还可以是强迫受害者使用攻击者设定的一个有效会话,以此来获得用户的敏感信息。


会话固定的sessionid在登录前后保持不变。
防范办法:
在用户登录成功后重新创建一个sessionid;
登录前的匿名会话强制失效;
Sessionid与浏览器绑定,浏览器有所变化,就立即重置;
Sessionid与IP绑定,IP有变化,就立即重置