WEB服务器在提供服务时,访问可能来自世界任何一个角落,如果网站所有页面都向所有人开放,似乎整个提供服务的过程看上去并没有什么值得留意的地方。但如果网站拥有自己的角色/权限系统呢?

  • 某些资源/页面只能登录的人访问;
  • 某些资源/页面不仅需要登录,还需要用户具有特别的权限;
  • ……

比较常见/用户友好的业务逻辑是:用户一旦登录,无论他打开什么页面,都能被网站识别出身份来(是否登录、用户组是什么、是否有权限访问这个页面)。

这个过程中,起作用的就是session——用一个不太精准的类比,可以将session想象成一条访客和服务器之间的一对一通道,一端是服务器,另一端是特定的访客,正常情况下永远不可能会是别人,一旦这名访客的访问结束,这条通道便可以销毁。

*session本质上是一个特殊的cookie,相对于普通cookie,它无需手工设置有效期,而是由服务器决定何时销毁,当然也可以永久保存,只是一般不会这么做,因为它会带来额外的、不必要的服务器开销,用户越多开销越大;

* 这个cookie的值是服务器为访客专门创建的一个key,对应了服务器为这名访客单独开辟的一个空间,不同访客之间相互独立,在这个空间可以存放任何该名访客独有的数据,也可以用来进行身份/权限标记。

当服务器收到访客的第一个HTTP Request,会在Response里在访客的客户端(浏览器)设置一个 Cookie,有效期截止到Session结束。这样浏览器在后续进行请求时,都会带上这个特殊的Cookie,服务器也能识别出访客的真实身份,并可以在这位访客发起请求时,按需访问存储在session中的内容。

* Response返回cookie的动作其实就是在ResponseHeaders中添加一个 名为Set-Cookie的键值对,值的内容是所有cookie。

* 如果浏览器禁用了cookie,sessionid将会保存到URL中,地址栏的地址末尾会多出一个参数 &sessionid=xxxxxx。

既然session是一把钥匙,那么我复制了这把钥匙,是否就可以随意出入这个房间了呢?答案是肯定的。这种行为一般用在以下的场景里:

  • 劫持管理员的session,获得管理员的权限,进入管理后台(我不会,别问我);
  • 请求服务器资源时,保持登录状态,免去登录过程,比如写爬虫爬取需要登录才可以访问的内容(我也不会,别问我)。

以一个scm-manager站点做示例:

* scm manager是一个集成的代码管理方案,包含Git,Subversion等代码仓库管理功能,以及权限管理功能。它也提供了REST风格的API: 
https://docs.scm-manager.org/restdocs/current/

* 除了登录接口外,所有api请求都需要在登录后才可以访问

首先,访问登录接口,ResponseHeaders会包含用户cookie,当中就有sessionid,将sessionid或整个cookie保存下来。

一旦有了sessionid,就可以在今后的请求中带上它(如果webclient支持cookie,就把它放到cookie;如果不支持cookie,需要构造cookie,并将set-cookie键值对添加到header,这样也能被服务器正常识别出来),这就实现了session保持的功能。

安全:

既然xss攻击可以窃取cookie和session,那么如何防护呢?

抛开对特殊请求的构造进行识别、过滤和转义不讲,单从cookie防范上来讲,服务器端可以为cookie开启http-only设置,这样将无法从js获取到cookie内容。