会话固定攻击(session fixation attack)及解决办法

1 Cookie 的工作过程

Cookie的传递用到了两个字段: 请求头字段Cookie和响应头字段Set-Cookie

当用户浏览器第一次访问服务器的时候,服务器肯定是不知道他的身份的。所以,就要创建一个独特的身份识别数据,格式是"key=value", 然后放进Set-Cookie字段里。随着响应报文一同发给浏览器。

浏览器收到响应报文,看到里面的Set-Cookie,知道这时服务器给的身份标识,于是就保存起来,下次再请求的时候 就自动把这个值放进Cookie字段里发给服务器。

因为第二次请求里面有了 Cookie 字段,服务器就知道这个用户不是新人,之前来过,就可以拿出 Cookie 里的值,识别出用户的身份,然后提供个性化的服务。

服务器有时会在响应头里添加多个 Set-Cookie,存储多个**“key=value**”。但浏览器这边发送时不需要用多个 Cookie 字段,只要在一行里用“;”隔开就行。

示意图如下:
在这里插入图片描述
从上图得知,Cookie是由浏览器负责存储的,而不是操作系统。

2.session 介绍

session 是服务端的一个概念,服务端生成session都会生成一个对应的SessionID,这个SessionId 会通过Cookie传递给前端,前端以后发送请求的时候,都会带上sessionID的参数,服务端看到请求中带了sessionId, 就会根据这个sessionID 取出对应的session信息。

浏览器的关闭不会导致服务器的session失效,服务端session失效只有两种情况:一是session过期,二
是session的invalidate方法,还有就是重启客户端。

为什么我们平时觉得浏览器关闭了,session就失效了吗?这是因为浏览器里面的sessionID丢了,所以当浏览器再次访问服务器端的时候,服务器会重新给浏览器分配一个sessionId ,这个sessionId和 之前的那么session对应不上,所以用户就会感觉session失效。

session的认证的流程如下图:
在这里插入图片描述
1.浏览器发送登录请求 /user/login

2.登录成功后,服务端将session存在内存中。

3.然后服务端返回Set-Cookie 携带 sessionId 字段

4.登录后,浏览器每发送都会在请求字段Cookie上自动带上sessionId

5.浏览器拿到sessionID 后,去内存session中回去用户信息,如果匹配不上,说明没有登录。

3.会话固定攻击

会话固定(Session fixation)是一种诱骗受害者使用攻击者指定的会话标识(SessionID)的攻击手段。这是攻击者获取合法会话标识的最简单的方法。(让合法用户使用黑客预先设置的sessionID进行登录,从而是Web不再进行生成新的sessionID,从而导致黑客设置的sessionId变成了合法桥梁。)

Servlet容器允许URL地址后面增加;JSESSIONID=...的方式携带session信息。

攻击步骤
在这里插入图片描述
1.攻击者打开一个登录页面

2.服务端会返回攻击者一个sessionId = 123xyz

3.攻击者发送一个伪装连接并带上sessionId

4.然后正常用户接到后,点击进行登录

5.这时候服务端sessionID=123xyz的session已经存在

6.这时,有了这个sessionID ,攻击者就可以正大光明的访问漏洞系统了。

攻击原理: 登录后的sessionId和登录前的SessionId 没有变化

4. 解决方案

解决办法是在登录的时候,将原来的session作废,生成新的session。这里要注意的是,使用logout不能使session作废,而要用session的stop方法。代码如下:

在 Spring Security中,防御会话固定攻击很简单,只需要下面配置即可:

@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                .loginPage("/signIn")
                .and()
                .cors()
                .and().sessionManagement().sessionFixation().migrateSession()
                .sessionRegistry(sessionRegistry);
    }
}

springSecurity 默认已经开启了该配置,主要利用SessionManager这个配置其来完成的。
在这里插入图片描述

  • none: 该策略对会话不做任何变动,登录之后会沿用旧的session;

  • newSession: 用户登录后会创建一个新的session;

  • migrateSession: 默认策略,用户登录后创建一个新的session,并将旧session中的数据复制过来;

  • changeSessionId: 表示 session 不变,不会创建新的session,但是会修改 sessionid,内部使用由Servlet容器提供的会话固定保护。

默认的防御策略是 migrateSession ,在用户匿名访问的时候是一个 sessionid,当用户成功登录之后,
又是另外一个 sessionid,这样就可以有效避免会话固定攻击。

Spring Security 之所以可以实现上述防御效果,主要是从以下三个方面来完成:

  1. 利用 StrictHttpFirewall 防火墙,如果发现请求地址中带有 “;”,则该请求会被直接拒绝;这样可以阻止请求URL带上SessionID

  2. 响应的 Set-Cookie 字段中有 HttpOnly 属性,这种方式会避免通过 XSS 攻击来获取 Cookie 中的会话信息,进而达成会话固定攻击。

  3. 登录成功后,改变sessionId 。既然问题是由于 sessionid 不变导致的,那我们就让 sessionid 变一下,利用Spring Security提供的防御会话固定攻击的策略即可实现。

我们看下session策略的源代码。

ChangeSessionIdAuthenticationStrategy中的onAuthentication方法其实是由父类AbstractSessionFixationProtectionStrategy实现的。这个方法就是防止固定会话攻击,会一直不停的修改你的sessionId。

public void onAuthentication(Authentication authentication,
                        HttpServletRequest request, HttpServletResponse response) {
                boolean hadSessionAlready = request.getSession(false) != null;
                //1.session不存在直接返回
                if (!hadSessionAlready && !alwaysCreateSession) {
                        return;
                }
                HttpSession session = request.getSession();
                //2.如果session存在的话则创建一个新的session覆盖老的session,sessionId也会改变
                if (hadSessionAlready && request.isRequestedSessionIdValid()) {
                        String originalSessionId;
                        String newSessionId;
                        Object mutex = WebUtils.getSessionMutex(session);
                        synchronized (mutex) {
                                // We need to migrate to a new session
                                originalSessionId = session.getId();
 
                                session = applySessionFixation(request);
                                newSessionId = session.getId();
                        }
                        if (originalSessionId.equals(newSessionId)) {
                                logger.warn("Your servlet container did not change the session ID when a new session was created. You will"
                                                + " not be adequately protected against session-fixation attacks");
                        }
                        onSessionChange(originalSessionId, session, authentication);
                }
        }

参考资源链接:[华为WEB应用系统安全规范V1.5详解与修订历史](https://wenku.youkuaiyun.com/doc/6hj2815bd8?utm_source=wenku_answer2doc_content) 会话固定攻击是一种安全漏洞,攻击者可以通过设置特定的会话ID,并诱导用户使用这个ID继续进行操作,从而劫持用户的会话。根据华为WEB应用系统安全规范V1.5,开发者可以在C/C++和Java开发中采取以下安全编码实践来防御会话固定攻击: 1. **生成新的会话ID**:每当用户进行身份验证成功后,应用程序应立即生成一个新的随机会话ID,并废弃旧的会话ID。这一步骤是为了确保攻击者无法使用已知的会话ID进行会话固定。 2. **使用HTTPS协议**:确保所有的通信都通过HTTPS进行,这样可以防止会话ID通过中间人攻击(MITM)被截获。 3. **避免使用客户端生成的会话ID**:会话ID不应由客户端生成或提供,所有的会话ID必须由服务器端控制,以防止攻击者通过注入方式设置会话ID。 4. **会话ID与用户身份验证状态绑定**:会话ID应与用户的身份验证状态绑定,一旦用户登出,应立即使会话ID无效,并且所有的会话相关数据也应被清除。 5. **定时更换会话ID**:即使用户保持在线,也应定时更换会话ID,以减少会话固定攻击的风险。 6. **限制会话生存时间**:为会话设置一个合理的生存时间,超过时间后即使会话未被主动销毁,也会自动失效。 7. **日志记录和监控**:对所有会话ID的生成和使用进行日志记录,并实施监控机制,以便及时发现异常行为。 下面给出一个简单的示例代码,演示在Java中如何生成新的会话ID并替换旧的会话ID: ```java // 假设这是一个用户登录成功后执行的方法 public void onUserLogin(HttpServletRequest request, HttpServletResponse response) { // 移除旧的会话ID request.getSession().invalidate(); // 创建新的会话 HttpSession newSession = request.getSession(true); // 生成新的随机会话ID String newSessionId = UUID.randomUUID().toString(); newSession.setId(newSessionId); // 其他业务逻辑... } // 当用户登出时 public void onUserLogout(HttpSession session) { if (session != null) { session.invalidate(); // 使当前会话失效 } } ``` 通过遵循华为WEB应用系统安全规范V1.5提供的安全编码实践,开发者可以有效地防御会话固定攻击,增强Web应用的整体安全性。此外,建议开发者深入学习《华为WEB应用系统安全规范V1.5详解与修订历史》,以便更好地理解这些安全措施,并将它们应用到日常开发中去。 参考资源链接:[华为WEB应用系统安全规范V1.5详解与修订历史](https://wenku.youkuaiyun.com/doc/6hj2815bd8?utm_source=wenku_answer2doc_content)
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半夏_2021

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值