会话固定攻击与防御

什么是会话固定攻击

会话固定攻击(Session fixation attacks)是一种潜在的风险,恶意攻击者有可能通过访问当前应用程序来创建会话,然后诱导用户以相同的会话 ID 登录(通常是将会话 ID 作为参数放在请求链接中,然后诱导用户去单击),进而获取用户的登录身份。

举一个简单的会话固定攻击的例子(以 www.javaboy.org 为例,此网站为笔者所有):

  1. 攻击者自己可以正常访问 javaboy 网站,在访问的过程中,网站给攻击者分配了一个 sessionid。

  2. 攻击者利用自已拿到的 sessionid 构造一个 javaboy 网站的链接,并把该链接发送给受害者。

  3. 受害者使用该链接登录 javaboy 网站(该链接中含有 sessionid),登录成功后,一个合法的会话就成功建立了。

  4. 攻击者利用手里的 sessionid 冒充受害者。

在这个过程中,如果 javaboy 网站支持 URL 重写,那么攻击还会变得更加容易。

什么是 URL 重写?用户如果在浏览器中禁用了 cookie,那么 sessionid 自然也用不了,所以有的服务端就支持把 sessionid 放在请求地址中,类似下面这样:

http://www.javaboy.org;jsessionid=xxxxxx

如果服务端支持这种 URL 重写,那么对于攻击者来说,按照上面的攻击流程,构造一个这样的地址就太容易了。

会话固定攻击防御策略

Spring Security 中从三方面入手防范会话固定攻击:

  1. Spring Security 中默认自带了 Http 防火墙,如果 sessionid 放在地址栏中,这个请求就会直接被拦截下来(本书第 8 章会详细分析 Http 防火墙)。

  2. 在 Http 响应的 Set-Cookie 字段中有 httpOnly 属性,这样避免了通过 XSS 攻击来获取 Cookie 中的会话信息,进而达成会话固定攻击(在第 6 章的 RememberMe 认证中,服务端返回令牌信息时也设置了 httpOnly 属性为 true)。

  3. 既然会话固定攻击是由于 SessionId 不变导致的,那么其中一个解决办法就是在用户登录成功后,改变 SessionId,Spring Security 中默认实现了该种方案,实现类就是 7.2 节所讲的 ChangeSessionIdAuthenticationStrategy。

前两种都是默认行为,一般来说不需要做更改。第三种方案,Spring Security 中有几种不同的配置策略,我们先来看一下配置方式:

http.sessionManagement().sessionFixation().changeSessionId();

通过 sessionFixation() 方法开启会话固定攻击防御的配置,一共有四种不同的策略,不同策略对应了不同的 SessionAuthenticationStrategy:

  1. changeSessionId():用户登录成功后,直接修改 HttpSession 的 SessionId 即可,默认方案即此,对应的处理类是 ChangeSessionIdAuthenticationStrategy。

  2. none():用户登录成功后,HttpSession 不做任何变化,对应的处理类是 NullAuthenticatedSessionStrategy。

  3. migrateSession():用户登录成功后,创建一个新的 HttpSession 对象,并将旧的 HttpSession 中的数据拷贝到新的 HttpSession 中,对应的处理类是 SessionFixationProtectionStrategy。

  4. newSession():用户登录成功后,创建一个新的 HttpSession 对象,对应的处理类也是 SessionFixationProtectionStrategy,只不过将其里边的 migrateSessionAttributes 属性设置为 false。需要注意的是,该方法并非所有的属性都不拷贝,一些 Spring Security 使用的属性,如请求缓存,还是会从旧的 HttpSession 上复制到新的 HttpSession。

这四种策略,无论使用哪种,都相当于配置了一个 SessionAuthenticationStrategy,在 7.2.2 小节的分析中大家已经知道,默认使用的是 ChangeSessionIdAuthenticationStrategy,如果开发者在这里配置了其他类型的 SessionAuthenticationStrategy,就会替代掉默认使用的 ChangeSessionIdAuthenticationStrategy。

一般来说,我们使用 Spring Security 默认的方案就可以防御会话固定攻击了,即什么都不做,就可以防御会话固定攻击,这也是 Spring Security 强大之处!