【问题标题】:HttpSessionSecurityContextRepository - No HttpSession, only in ChromeHttpSessionSecurityContextRepository - 无 HttpSession,仅在 Chrome 中
【发布时间】:2021-04-10 15:15:31
【问题描述】:

我有一个 Spring Boot 应用程序,步骤如下:

  1. 用户登录到应用程序
  2. 用户按下按钮即可用卡支付一定金额
  3. 用户正在重定向到卡处理/支付站点,他必须在其中填写卡号、日期和其他内容
  4. 成功后,卡片网站将重定向到应用程序的反向引用,位于 /card-response
  5. spring 控制器映射在 /card-response 过程中,进一步处理支付结果并结束支付循环

问题:

在 Mozilla Firefox 中一切正常

在 Chrome 浏览器中第一次似乎没问题(所有步骤 1-5),但经过多次(可以是第二次、第三次或更多随机方式)应用程序显示登录页面(在第 4 步返回时application /card-response) 作为用户未经身份验证。

如果我在步骤 4 之前和之后(在 Application->Cookies 处)检查浏览器中的会话 cookie (JSESSIONID) 并且相同,未更改。 此外,在应用程序显示登录页面后,如果我直接在浏览器中输入 URL /card-response,我可以在没有登录页面的情况下访问应用程序,因此应用程序认为我已通过身份验证

来自spring应用日志:

DEBUG org.springframework.security.web.access.ExceptionTranslationFilter@4f5a3111, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@3fdb1ce4]] (1/1)
DEBUG org.springframework.security.web.FilterChainProxy - Securing POST /card-response
TRACE org.springframework.security.web.FilterChainProxy - Invoking WebAsyncManagerIntegrationFilter (1/13)
TRACE org.springframework.security.web.FilterChainProxy - Invoking SecurityContextPersistenceFilter (2/13)
TRACE org.springframework.security.web.context.HttpSessionSecurityContextRepository - **No HttpSession currently exists**
TRACE org.springframework.security.web.context.HttpSessionSecurityContextRepository - Created SecurityContextImpl [Null authentication]
DEBUG org.springframework.security.web.context.SecurityContextPersistenceFilter - Set SecurityContextHolder to empty SecurityContext

在 WebSecurityConfig 我有

http
          .authorizeRequests()
             .antMatchers("/resources/free/**").permitAll()
             .antMatchers("/rest-mock/**").permitAll()
             .antMatchers("/reset-password-init").permitAll()
             .antMatchers("/reset-password/**").permitAll()
             .antMatchers("/remote-login/**").permitAll()
             .antMatchers("/check-certificate/**").permitAll()
              .anyRequest().authenticated()
              .and().formLogin().loginPage("/login").successHandler(successHandler).permitAll()
             .and().exceptionHandling().accessDeniedPage("/logout")
             .and().logout().invalidateHttpSession(true).clearAuthentication(true).deleteCookies("JSESSIONID").permitAll()
              .and().csrf()
              .ignoringAntMatchers("/card-response/**","/rest-mock/**");

如果步骤 4 没问题(始终使用 Firefox 访问,有时使用 Chrome 访问),则 Spring 应用程序日志为:

DEBUG org.springframework.security.web.FilterChainProxy - Securing GET /card-response
TRACE org.springframework.security.web.FilterChainProxy - Invoking WebAsyncManagerIntegrationFilter (1/13)
TRACE org.springframework.security.web.FilterChainProxy - Invoking SecurityContextPersistenceFilter (2/13)
TRACE org.springframework.security.web.context.HttpSessionSecurityContextRepository - Retrieved SecurityContextImpl [Authentication=UsernamePasswordAuthenticationToken [Principal=User [id=28327, user_name=xxxxxxxxxx, first_name=xxxxxxxxxx, last_name=xxxxxxxxxx, email=xxxxx@domain.ro], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=D24B7748BA6C2C59B1C4FAB3D16C6B19], Granted Authorities=[Role [id=3, name=Lawyer]]]] from SPRING_SECURITY_CONTEXT
DEBUG org.springframework.security.web.context.SecurityContextPersistenceFilter - Set SecurityContextHolder to SecurityContextImpl [Authentication=UsernamePasswordAuthenticationToken [Principal=User [id=28327, user_name=xxxxxxxxxx, first_name=xxxxxxxxxx, last_name=xxxxxxxxxx, email=xxxxx@domain.ro], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [SessionId=D24B7748BA6C2C59B1C4FAB3D16C6B19], Granted Authorities=[Role [id=3, name=Lawyer]]]]
TRACE org.springframework.security.web.FilterChainProxy - Invoking HeaderWriterFilter (3/13)

所以这个上下文中的会话不为空,一切正常

问题是为什么 spring security 获取空会话并记录“当前不存在 HttpSession”,但在 Chrome 浏览器中,会话 cookie 在开始时没有改变,在第 1 步。

对于第 4 步的成功,请求标头包含 cookie:

POST /caav_interface/card-response HTTP/1.1
Host: localhost:8081
Connection: keep-alive
Content-Length: 281
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cookie: JSESSIONID=7B0E48E550B98EAE6CBF2D7E2AB76B59

对于不成功的请求不包含它:

POST /caav_interface/card-response HTTP/1.1
Host: localhost:8081
Connection: keep-alive
Content-Length: 281
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9

所以 Chrome 似乎并不总是在标头中传递 cookie。

【问题讨论】:

  • Spring Security 不管理会话,因此它并不真正掌握在 Spring Security 手中。您收到的错误消息意味着当 Spring Security 向 Servlet API 询问会话时,没有返回任何内容。如果您也在使用该模块,您的网络流量可能是寻找问题的更好地方,或者可能是您的 Spring Session 配置。
  • 嗨,你能指导我调试这个需要什么信息吗?在浏览器会话中,cookie 存在且未更改,那么为什么会话为空?为什么在 Firefox 中一切正常?
  • 不同的事情可以使应用服务器找不到会话。这两个应用程序是否在同一个域(例如 localhost)上,它们是否都有 JSESSIONID?您的应用程序是否在代理后面?您是否在 JSESSIONID cookie 上使用 SameSite 属性?如果您可以分享成功和失败握手的网络流量样本,或许会有所帮助。
  • 不,第一个应用程序在本地主机上,卡应用程序是远程的
  • 我用一些网络流量编辑了我的问题

标签: spring spring-boot spring-security


【解决方案1】:

解决方案:

没有 SameSite 属性的 JSESSIONID cookie 被 Chrome 考虑禁止在不同站点之间传递。

因此 cookie 必须具有属性“SameSite=None; Secure”才能在站点之间传递它。
有时在 Chrome 中运行的原因是 Chrome 在最初的 1 或 2 分钟内会在站点之间传递它。

需要安全属性,因为 Chrome 认为在没有 SSL/TLS 上下文的站点之间传递 cookie 是不安全的。
考虑到对于本地测试/开发,您必须省略此属性或在 Firefox 浏览器上进行测试。

在java中的实现: 从 SavedRequestAwareAuthenticationSuccessHandler 覆盖方法中放入 onAuthenticationSuccess

Collection<String> headers = response.getHeaders(HttpHeaders.SET_COOKIE);
        boolean firstHeader = true;
        // there can be multiple Set-Cookie attributes
        for (String header : headers) {
            if (firstHeader) {
                response.setHeader(HttpHeaders.SET_COOKIE,
                        String.format("%s; %s", header, "SameSite=None; Secure"));
                firstHeader = false;
                continue;
            }
            response.addHeader(HttpHeaders.SET_COOKIE,
                    String.format("%s; %s", header, "SameSite=None; Secure"));
        }

感谢 jzheaux 为我指明了正确的方向!

希望它有所帮助,我为此花了很多时间

【讨论】:

    猜你喜欢
    • 2016-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-22
    • 2015-10-30
    • 2014-01-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多