HttpSession
HttpSession 是一个服务端的概念,
服务端生成的 HttpSession 都会有一个对应的 sessionid,
这个 sessionid 会通过 cookie 传递给前端,
前端以后发送请求的时候,就带上这个 sessionid 参数
服务端看到这个 sessionid 就会把这个前端请求和服务端的某一个 HttpSession 对应起来,形成“会话”的感觉。
浏览器关闭并不会导致服务端的 HttpSession 失效,
想让服务端的 HttpSession 失效,要么手动调用 HttpSession#invalidate 方法;要么等到 session 自动过期;要么重启服务端。
但是为什么有的人会感觉浏览器关闭之后 session 就失效了呢?
这是因为浏览器关闭之后,保存在浏览器里边的 sessionid 就丢了(默认情况下),
所以当浏览器再次访问服务端的时候,服务端会给浏览器重新分配一个 sessionid ,
这个 sessionid 和之前的 HttpSession 对应不上,所以用户就会感觉 session 失效。
注意前面我用了一个「默认情况下」,也就是说,我们可以通过手动配置,让浏览器重启之后 sessionid 不丢失,但是这样会带来安全隐患,所以一般不建议
会话固定攻击
正常来说,只要你不关闭浏览器,并且服务端的 HttpSession 也没有过期,那么维系服务端和浏览器的 sessionid 是不会发生变化的,
而会话固定攻击,则是利用这一机制,
借助受害者用相同的会话 ID 获取认证和授权,然后利用该会话 ID 劫持受害者的会话以成功冒充受害者,造成会话固定攻击。
一般来说,会话固定攻击的流程是这样,以淘宝为例:
- 攻击者自己可以正常访问淘宝网站,在访问的过程中,淘宝网站给攻击者分配了一个 sessionid。
- 攻击者利用自己拿到的 sessionid 构造一个淘宝网站的链接,并把该链接发送给受害者。
- 受害者使用该链接登录淘宝网站(该链接中含有 sessionid),登录成功后,一个合法的会话就成功建立。
- 攻击者利用手里的 sessionid 冒充受害者。
在这个过程中,如果淘宝网站支持 URL 重写,那么攻击还会变得更加容易。
什么是 URL 重写?
就是用户如果在浏览器中禁用了 cookie,那么 sessionid 自然也用不了了,
所以有的服务端就支持把 sessionid 放在请求地址中:
例如:
http://www.taobao.com;jsessionid=xxxxxx
如果服务端支持这种 URL 重写,那么对于攻击者来说,按照上面的攻击流程,构造一个这种地址简直太简单不过了。
不过这种请求地址大家在 Spring Security 中应该很少见到(原因请看下文),但是在 Shiro 中可能多多少少有见过。
如何防御
这个问题的根源在 sessionid 不变,
如果用户在未登录时拿到的是一个 sessionid,登录之后服务端给用户重新换一个 sessionid,就可以防止会话固定攻击了。
如果你使用了 Spring Security ,其实是不用担心这个问题的,因为 Spring Security 中默认已经做了防御工作了。
Spring Security 中的防御主要体现在三个方面:
- 就是 StrictHttpFirewall,请求地址中有 ; 请求会被直接拒绝。
- 就是响应的 Set-Cookie 字段中有 HttpOnly 属性,这种方式避免了通过 XSS 攻击来获取 Cookie 中的会话信息进而达成会话固定攻击。
- 则是让 sessionid 变一下。既然问题是由于 sessionid 不变导致的,那我就让 sessionid 变一下
配置
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated()
.and() //所有请求都需要认证才能访问
.formLogin()
.permitAll()
.and()
.sessionManagement()
.sessionFixation()
.migrateSession()//配置防御会话固定攻击
;
}
sessionFixation后面有四个方法
- migrateSession 表示在登录成功之后,创建一个新的会话,然后将旧的 session 中的信息复制到新的 session 中,「默认即此」。
- none 表示不做任何事情,继续使用旧的 session。
- changeSessionId 表示 session 不变,但是会修改 sessionid,这实际上用到了 Servlet 容器提供的防御会话固定攻击。
- newSession 表示登录后创建一个新的 session。
默认的 migrateSession ,在用户匿名访问的时候是一个 sessionid,当用户成功登录之后,又是另外一个 sessionid,这样就可以有效避免会话固定攻击。
这三种方案,可以让我们有效避免会话固定攻击!