会话固定攻击与防御
什么是会话固定攻击
会话固定攻击(Session fixation attacks)是一种潜在的风险,恶意攻击者有可能通过访问当前应用程序来创建会话,然后诱导用户以相同的会话 ID 登录(通常是将会话 ID 作为参数放在请求链接中,然后诱导用户去单击),进而获取用户的登录身份。
举一个简单的会话固定攻击的例子(以 www.javaboy.org 为例,此网站为笔者所有):
-
攻击者自己可以正常访问 javaboy 网站,在访问的过程中,网站给攻击者分配了一个 sessionid。
-
攻击者利用自已拿到的 sessionid 构造一个 javaboy 网站的链接,并把该链接发送给受害者。
-
受害者使用该链接登录 javaboy 网站(该链接中含有 sessionid),登录成功后,一个合法的会话就成功建立了。
-
攻击者利用手里的 sessionid 冒充受害者。
在这个过程中,如果 javaboy 网站支持 URL 重写,那么攻击还会变得更加容易。
什么是 URL 重写?用户如果在浏览器中禁用了 cookie,那么 sessionid 自然也用不了,所以有的服务端就支持把 sessionid 放在请求地址中,类似下面这样:
http://www.javaboy.org;jsessionid=xxxxxx
如果服务端支持这种 URL 重写,那么对于攻击者来说,按照上面的攻击流程,构造一个这样的地址就太容易了。
会话固定攻击防御策略
Spring Security 中从三方面入手防范会话固定攻击:
-
Spring Security 中默认自带了 Http 防火墙,如果 sessionid 放在地址栏中,这个请求就会直接被拦截下来(本书第 8 章会详细分析 Http 防火墙)。
-
在 Http 响应的 Set-Cookie 字段中有 httpOnly 属性,这样避免了通过 XSS 攻击来获取 Cookie 中的会话信息,进而达成会话固定攻击(在第 6 章的 RememberMe 认证中,服务端返回令牌信息时也设置了 httpOnly 属性为 true)。
-
既然会话固定攻击是由于 SessionId 不变导致的,那么其中一个解决办法就是在用户登录成功后,改变 SessionId,Spring Security 中默认实现了该种方案,实现类就是 7.2 节所讲的 ChangeSessionIdAuthenticationStrategy。
前两种都是默认行为,一般来说不需要做更改。第三种方案,Spring Security 中有几种不同的配置策略,我们先来看一下配置方式:
http.sessionManagement().sessionFixation().changeSessionId();
通过 sessionFixation() 方法开启会话固定攻击防御的配置,一共有四种不同的策略,不同策略对应了不同的 SessionAuthenticationStrategy:
-
changeSessionId():用户登录成功后,直接修改 HttpSession 的 SessionId 即可,默认方案即此,对应的处理类是 ChangeSessionIdAuthenticationStrategy。
-
none():用户登录成功后,HttpSession 不做任何变化,对应的处理类是 NullAuthenticatedSessionStrategy。
-
migrateSession():用户登录成功后,创建一个新的 HttpSession 对象,并将旧的 HttpSession 中的数据拷贝到新的 HttpSession 中,对应的处理类是 SessionFixationProtectionStrategy。
-
newSession():用户登录成功后,创建一个新的 HttpSession 对象,对应的处理类也是 SessionFixationProtectionStrategy,只不过将其里边的 migrateSessionAttributes 属性设置为 false。需要注意的是,该方法并非所有的属性都不拷贝,一些 Spring Security 使用的属性,如请求缓存,还是会从旧的 HttpSession 上复制到新的 HttpSession。
这四种策略,无论使用哪种,都相当于配置了一个 SessionAuthenticationStrategy,在 7.2.2 小节的分析中大家已经知道,默认使用的是 ChangeSessionIdAuthenticationStrategy,如果开发者在这里配置了其他类型的 SessionAuthenticationStrategy,就会替代掉默认使用的 ChangeSessionIdAuthenticationStrategy。
一般来说,我们使用 Spring Security 默认的方案就可以防御会话固定攻击了,即什么都不做,就可以防御会话固定攻击,这也是 Spring Security 强大之处!