防止未经授权的http请求重定向到/错误设置会话cookie - spring boot - spring security

min*_*int 7 java spring-security unauthorized session-cookies spring-boot

语境

我的申请遇到了一些问题。我们使用 Spring Boot 2.4.10 和 Spring Security 5.4.8。我们使用 cookie 与应用程序交互。

我们有一个存储在src/main/resources其中的前端应用程序,其中包括连接到/api/v1/notification.

我的配置

application.properties文件:

# cookie-related settings
server.servlet.session.cookie.name=mySessionCookie
server.servlet.session.cookie.path=/
server.servlet.session.cookie.http-only=true
server.servlet.session.cookie.secure=true
Run Code Online (Sandbox Code Playgroud)
# cookie-related settings
server.servlet.session.cookie.name=mySessionCookie
server.servlet.session.cookie.path=/
server.servlet.session.cookie.http-only=true
server.servlet.session.cookie.secure=true
Run Code Online (Sandbox Code Playgroud)

问题

当没有用户登录时,前端会尝试定期访问 websocket 端点以打开连接。

第一个api/v1/notification结束重定向到/error端点,该端点返回HttpServletResponse带有“Set-Cookie”标头(我认为这可能是在第一个请求中设置的匿名 cookie?)和401状态。我无法改变这种行为。

以下请求api/v1/notification在标头中使用此 cookie(当用户未登录时)。这些请求也会重定向到/error端点,该端点每次都会返回HttpServletResponse401状态,但这里不包含“Set-Cookie”标头。

用户使用授权标头登录后,响应将设置正确的 cookie 并在以下请求中使用。

问题是,有时设置的 cookie 会突然再次更改为无效 cookie,并且使用此新的无效 cookie 完成的后续请求会重定向到登录页面。

检查代码后,似乎发生了一个旧api/v1/notification请求(在登录请求之前),其中包含无效的 cookie(匿名请求,在登录之前存在)。

该请求被重定向到/error端点:这里再次HttpServletResponse出现401状态,并且包含一个 Set-Cookie 标头,该标头正在修改浏览器 cookie(替换好的 cookie)。

以下是问题的示意图,希望可以更容易理解。

在此输入图像描述

预期行为

我想阻止未经授权的请求设置会话 cookie。

如果先前的请求以 401 代码响应也没关系,但我不希望它更改当前设置的 cookie。

我试过...

  • 我尝试ErrorController通过返回 a来扩展ResponseEntity,其中包含输入中HttpServletResponse除“Set-Cookie”标头之外的所有标头。这是行不通的。

  • 我还尝试修改我的配置以禁用匿名请求:

    
    @Configuration
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
      private final String[] authorizedWithoutAuth = {
          "/",
          "/index.html",
          "/static/**"
      };
    
      @Override
      protected void configure(HttpSecurity http) throws Exception {
        http.httpBasic()
            .and()
              .authorizeRequests()
              .antMatchers(authorizedWithoutAuth).permitAll()
              .anyRequest().authenticated()
            .and()
              .csrf().disable()
            .and()
            .logout().logoutUrl("/api/v1/logout").invalidateHttpSession(true)
            .deleteCookies("mySessionCookie");
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    但是会话cookie仍然是这样设置的,有401请求。

  • 我还尝试使用@ControllerAdvice来处理异常,但这些异常是由 Spring Security 在 中抛出的AbstractSecurityInterceptor,如响应中所述。

感谢大家抽出时间。抱歉帖子太长了:)

min*_*int 4

我开始深入研究 Spring Security 库,并注意到会话 cookie 是在HttpSessionRequestCache.saveRequest(...)方法中设置的:

public void saveRequest(HttpServletRequest request, HttpServletResponse response) {
  if (!this.requestMatcher.matches(request)) {
    if (this.logger.isTraceEnabled()) {
      this.logger.trace(LogMessage.format("Did not save request since it did not match [%s]", this.requestMatcher));
    }
  } else {
    DefaultSavedRequest savedRequest = new DefaultSavedRequest(request, this.portResolver);
    if (!this.createSessionAllowed && request.getSession(false) == null) {
      this.logger.trace("Did not save request since there's no session and createSessionAllowed is false");
    } else {
      request.getSession().setAttribute(this.sessionAttrName, savedRequest);
      if (this.logger.isDebugEnabled()) {
        this.logger.debug(LogMessage.format("Saved request %s to session", savedRequest.getRedirectUrl()));
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

创建对象时会出现“Set-Cookie”标头DefaultSavedRequest。我将其更改WebSecurityConfig为以下内容:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  ...

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.httpBasic()
        .and()
          .requestCache().requestCache(getHttpSessionRequestCache()) // This is new
        .and()
          .authorizeRequests().antMatchers(authorizedWithoutAuth).permitAll()
          .anyRequest().authenticated()
        .and()
          .csrf().disable()
        .and()
          .logout().logoutUrl("/api/v1/logout").invalidateHttpSession(true)
          .deleteCookies("mySessionCookie");
  }


  public HttpSessionRequestCache getHttpSessionRequestCache()
  {
    HttpSessionRequestCache httpSessionRequestCache = new HttpSessionRequestCache();
    httpSessionRequestCache.setCreateSessionAllowed(false); // I modified this parameter 
    return httpSessionRequestCache;
  }
}
Run Code Online (Sandbox Code Playgroud)

现在可以了。使用授权标头登录时,cookie 设置正确,但所有具有无效会话 cookie 或过期会话 cookie 的请求都会返回响应,401而不会设置新的响应。

另外,读完这个答案后,我更好地理解了这createSessionAllowed是在做什么