Session原理、安全以及最基本的Express和Redis实现

Session原理、安全以及最基本的Express和Redis实现

Session基础概念


Session管理是Web Application的基础也是一个老生常谈的话题。为了方便后文的展开,更重要的是确认自己清晰的理解了整个Session管理的概念,我在此还是决定赘述的整个流程。如果你已经对于Session概念非常清晰的话,可以跳过本节不影响对于后文的理解。

HTTP协议在设计的时候是无状态的。这是一个很关键的概念,意味着服务器在处理请求的时候,并不关注这个请求是谁发来的。这对于以提供内容为核心的Web1.0,例如门户网站,非常适合。然而对于以应用服务为核心的Web 2.0而言,服务器端必须有能力从请求中提取出请求者的身份信息,以在请求者不用反复输入身份的情况下,提供连续的服务。

实现请求身份验证的方式很多,其中一种广泛接受的方式是使用服务器端产生的Session ID结合浏览器的Cookie实现对Session的管理,一般来说包括以下4个步骤:

  1. 服务器端的产生Session ID
  2. 服务器端和客户端存储Session ID
  3. 从HTTP Header中提取Session ID
  4. 根据Session ID从服务器端的Hash中获取请求者身份信息

enter image description here

上图是一个使用Redis Cluster来实现对Session管理的流程,但本质上除了redisMatrix.get和redisMatrix.set以外,和一般的Session管理流程是一致的。

简单来说,一个请求到达的时候,服务器会先判断是否带有Session信息。如果有,则根据Session ID去数据库中查找是否具有对应的用户身份信息。此处可能会出现Session失效、非法的Session信息等可能性,那么服务器视同无Ssession信息的情况,重新的产生一个随机的字符串,并且在Http返回头中写入新的Session ID信息。另一者,如果服务器成功获取了用户的身份信息则以该身份为请求者提供服务。

使用Express和Redis对Session管理的实现


Redis是一个非常适合用于Session管理的数据库。第一,它的结构简单,key-value的形式非常符合SessionID-UserID的存储;第二,读写速度非常快;第三,自身支持数据自动过期和清除;第四,语法、部署非常简单。基于以上原因,很多Session管理都是基于Redis实现的。

Session的安全问题


SessionId就如同请求者的身份证,一旦被攻击者恶意获得,攻击者便可以伪装成请求者对服务器发起请求,也就是我们经常听到的会话劫持(Session/Cookie Hijack)
关于会话劫持的原理推荐大家去看这篇文章

基于上述实现方法的Session管理,我认为基本上可以排除

  • 暴力破解SessionId
  • 恶意植入固定SessionId

两种可能,因为uid的库基本上可以保证SessionId的随机性;而传递SessionId则依赖HTTP请求头中的Cookie信息而非URL,同时在用户登录立刻更换SessionId。

唯一的可能性来源于Session的监听,而对于这种攻击有效的两种防止办法是:

  • Https
    很多网站仅仅在Login的阶段使用Https防止用户的用户名、密码信息被监听者获取,但是随后的SessionId同样有可能被监听者获取而伪造登录者的身份信息。因此更加推荐的方式是所有的信息传递全部使用Https实现,这样即使监听着截获了信息也无法破解其中的内容。关于如何使用NodeJS建立一个HTTPS的server可以参考《HTTPS的原理和NodeJS的实现》 这篇文章
  • httpOnly
    Express在options中提供了httpOnly的属性,此属性默认值为true,这个属性保证了Cookie的信息不能够通过JavaScript脚本获取。

参考:

  1. https://segmentfault.com/a/1190000002630691
  2. http://devco.re/blog/2014/06/03/http-session-protection/