您的位置:首页 > 其它

Web 安全登录

2016-05-15 01:22 169 查看

基本解决方案

绝大多数Web应用里面都有用户登录的功能。

由于HTTP(S)协议的特点,服务器没有办法锁定客户端,因为客户端对服务器发送HTTP(S)请求的时候,往往没有携带自身的信息,于是服务器想确认客户端的身份是有心无力的。

于是出现了在HTTP(S)报头中附带Cookie的一种做法,来帮助服务器识别客户端:

Created with Raphaël 2.1.0客户端客户端服务器服务器没有携带Cookie初次访问你这厮没有Cookie?我给你生成一个响应并要求客户端存储给定Cookie有了Cookie携带Cookie访问一些需要登录才能查看的资源查表发现这个Cookie没有与任何用户的联系说明还没登录!提示需要登录的响应登录携带Cookie、用户凭证发送登录请求记下了这个Cookie与XXX的暂时的联系登录成功!有了登记后的Cookie携带Cookie访问一些需要登录才能查看的资源查了之前维护的联系表,确认这个Cookie对应的用户是XXX正确回复资源。

这就是Web应用处理用户登录的解决方案。

Cookie是储存在用户的浏览器中的,通常还会带有一个域名:这个Cookie是哪个网站要求设置的

比如百度设定Cookie就有存储在www.baidu.com这个域名中,当你访问这个域名的时候,浏览器就会自动在HTTP(S)的请求报头中附上对应的Cookie,避免了不同网站之间Cookie的命名空间冲突。

安全与性能

现在问题来了,怎么在Cookie中存储一些信息比较好呢?

不妨先给出几个分析:

Cookie 不宜过大。

由于Cookie会附到每一次HTTP(S)请求中,若Cookie过多,会明显增重网络I/O的负担。

Cookie 不宜可读

由于Cookie在客户端本地可以很方便地被JavaScript修改,若Cookie可读,那么也很容易被恶意用户篡改(伪造)

Cookie 不宜与用户信息有关

如果Cookie的生成与用户的信息有关,即便Cookie加密到不可读,一旦算法被识破,就有一定几率被反推伪造,或者泄漏个人信息,有隐患。

由此我们可以有这样一个解决方案:

当用户访问时,随机生成一个足够强的Hash值作为Cookie,跟用户信息无关、且不可读、不易伪造。

在后端服务器维护一个以上述Hash值作为索引的集合。

在上述集合中缓存用户的个人信息。

当用户访问需要验证身份的资源时,服务器从集合中取出对应的Cookie,并检查缓存中的个人信息来确认身份。

当用户修改了个人信息时,更新缓存。

这个Hash值就相当于一个口令,通常我们称它为Session ID(会话ID)。意思就是维护一个客户端与服务器之间的会话,用一个足够离散的Hash值来防止撞表,通常来说,一个站点同时有效的会话数不超过其用户数的20%,而若Hash值的字符集是64,长度为40,Hash值有6440=2240=1.8∗107464^{40} = 2^{240} = 1.8 * 10^{74} 种可能,撞表成功的期望代价很高,可以认为是安全的。

万一这个人运气很好,撞表成功了,这意味着他能伪装成某个用户了,这跟暴力破解密码的行为是一致的,但这个SessionID是临时性的,随时可能失效,至少不会造成密码泄露(当然你不能在你的数据库中明文存储用户的密码或者提供API查询密码),当用户选择登出或者Session过期的时候,这个SessionID就会失效,撞表的结果就失去了意义。

关于中间人攻击,一般的做法是加密Cookie,最好使用HTTPS整个加密,这个不属于本文讨论范畴。

另外,这个Session ID确实足够短又足够好用,既不会给网络I/O造成什么严重的负担,也足够服务器来识别用户的身份。

困难的地方在于,设计一个安全的Hash算法是不容易的,没有足够好的数学功底就不要自己写Hash了。直接用现成的算法即可。除此之外,管理Session集合的内存也是不容易的,要正确地增删改Session对象,及时地释放空间……这其实是一个数据结构问题,考虑到查询性能等种种原因,也用别人已经开发好的比较好。

成熟的解决方案

Java Servlet 有 JSessionID 的设置,PHP也有PHPSessionID,NodeJS比较开放,Express有一个插件叫做
express-session
可以解决这个问题。

网上学 Session 的资料很多,在此不一一列举,只是想说明为什么要这样实现登录功能。怎么做是安全高效的以及为什么。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: