【问题标题】:User session mixed up :: Spring Security用户会话混淆 :: Spring Security
【发布时间】:2019-09-13 16:23:13
【问题描述】:

我们有一个 Web 应用程序(5 年以上),它使用 Spring Security (3.1) 功能对用户进行身份验证和授权。

  • 作为身份验证过程的一部分,我们创建一个随机的 20 个字符的访问代码 (ac) 和 5 个字符的用户编号 (un)
  • 身份验证成功后,我们重定向到另一个应用程序,传递访问代码、用户号作为查询参数
  • APP2根据访问码向各个用户显示信息

    下面是spring安全重定向的示例流程和示例格式:

重定向格式:

https://APP1_HOST:PORT/auth/j_spring_security_logout?redirectUrl=https://APP2_HOST/abc/AccessServlet?ac=astqcssq-Z-3R2LOFjy-&un=12345

身份验证的代码流程

@RequestMapping(value="/Authentication.do")
public String doWAuthentication(ModelMap model) {

    User user = super.getUser();        

    String url = app2Baseroot; // instance variable - APP2 Host name

    //generate parameters - static methods
    String accessCode = Utils.generateString(20);
    String userNo = Utils.generateUserNumber(5);

    //write authentication details for APP2 to retrieve
    userDao.saveAuthenticationDetails(user, accessCode, userNo);

    //Add redirection specifics - servlet name & query params
    try {
        url += java.net.URLEncoder.encode("AccessServlet?ac="+accessCode+"&un="+userNo, "UTF-8");
    } catch (UnsupportedEncodingException uee) {

        LOG.error("Unable to encode redirect URL: "+uee.toString());
    }

    //redirect via spring security logout
   // AuthBaseroot - Instance variable - APP1 host name
    return "redirect:"+AuthBaseroot+"j_spring_security_logout?redirectUrl="+url;
}

我们最近遇到了一个问题,即 USER 1 能够查看 USER 2 的详细信息,因为重定向 URL 混淆了。两个用户同时访问身份验证应用程序,即相同的小时、分钟、秒。

我们定义了自定义表单登录,将 always-use-default-target 属性设置为“true”,并在 spring security XML 中配置了自定义注销处理程序文件:

<sec:logout success-handler-ref="logoutSuccessHandler" invalidate-session="true" delete-cookies="JSESSIONID" />

LogoutSuccessHandler 扩展 SimpleUrlLogoutSuccessHandler 并覆盖 onLogoutSuccess。该方法所做的只是从 HttpServletRequest 获取重定向 url 并将其设置为

AbstractAuthenticationTargetUrlRequestHandler。 setDefaultTargetUrl(URL) 并调用 super 方法(super.onLogoutSuccess)。

public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
        Authentication authentication) throws IOException, ServletException {

    //Set redirection to APP2 url containing security params
    super.setDefaultTargetUrl(request.getParameter("redirectUrl"));

    super.onLogoutSuccess(request, response, authentication);
}
  • 我们的应用程序托管在 AWS 中,并使用经典 ELB,作为安全性的一部分,所有请求流都通过 incapsula imperva 进行
  • ELB 已为“应用程序生成的 cookie 粘性”启用粘性
  • 我们还在 ELB 层启用了访问日志并检查访问日志,我们可以看到 USER1、USER2 的重定向 URL 混淆了

以下是供 USER1、USER 2 参考的示例访问日志

用户 2:

2019-04-20T09:34:11.328056Z XXX.XXX.XX.XX:XXXXX XX.XXX.XXX.XXX:80 0.000171 0.050725 0.0001 302 302 0 321 
"GET https://APP1_HOST:PORT/auth/j_spring_security_logout?redirectUrl=https://APP2_HOST/link/AccessServlet%3Fac%3DWA-FF7WlNowjyu2R-XaU%26un%3D12345 
HTTP/1.1" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2

2019-04-20T09:34:11.413849Z XXX.XXX.XX.XX:XXXXX XX.XXX.XXX.XXX:80 0.000074 0.003343 0.000073 200 200 0 799 
"GET https://APP2_HOST/link/AccessServlet%3Fac%3DWA-FF7WlNowjyu2R-XaU%26un%3D12345
HTTP/1.1" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2

USER 2 访问日志证明来自 spring security logout j_spring_security_logout 的重定向 url 与实际重定向匹配。

用户 1

2019-03-26T09:34:11.349198Z XXX.XXX.XX.XX:XXXXX XX.XXX.XXX.XXX:80 0.000137 0.030374 0.00011 302 302 0 321
"GET https://APP1_HOST:PORT/auth/j_spring_security_logout?redirectUrl=https://APP2_HOST/link/AccessServlet%3Fac%3Dn--qcvnq-Z-3R2LOFjy-%26un%3D13267 
HTTP/1.1" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/73.0.3683.86 Safari/537.36" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2

2019-03-26T09:34:11.408386Z XXX.XXX.XX.XX:XXXXX XX.XXX.XXX.XXX:80 0.000066 0.007958 0.000077 200 200 0 1365 
"GET https://APP2_HOST/link/AccessServlet%3Fac%3DWA-FF7WlNowjyu2R-XaU%26un%3D12345 
HTTP/1.1" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/73.0.3683.86 Safari/537.36" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2

第一个语句显示 j_spring_security_logout 以及 USER 1 的正确重定向 URL,但随后对重定向 URL 的调用似乎与 USER 2 混淆了。由于用户详细信息基于访问代码 USER 1 是能够查看 USER 2 的详细信息。

到目前为止我们注意到的几件事:

  1. USER1、USER2 同时发送请求,即相同的小时、分钟、秒。从访问日志中,我们看到 USER 2 请求先发送,但就响应而言,USER 1 首先使用 USER 2 重定向 URL 获得响应。
  2. 访问代码生成没有太大问题,因为我们看到 USER1、USER2 的初始 spring 安全注销重定向似乎具有正确的详细信息
  3. 因此 ELB 不会修改除 X-Forwarded-* 标头以外的任何 HTTP 标头详细信息,这是我的理解
  4. USER1、USER2 请求均由同一个 EC2 实例处理。经典 ELB 的默认行为是将每个请求独立路由到负载最小的注册实例。由于我们已经配置了粘性会话功能,这使负载均衡器能够将用户的会话绑定到特定实例。这可以确保会话期间来自用户的所有请求都发送到同一个实例 参考:https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-sticky-sessions.html

以下是Authentication模块中使用的技术

  • Java – 1.6
  • Spring MVC、Spring Security(3.1 版)
  • Servlet API – 2.4
  • OC4J 服务器 (10.1.3.5)
  • 在 AWS 中部署 - 使用经典 ELB

我想知道问题是否出在 Spring 安全层(可能是注销处理程序),我们从 HttpServletRequest 对象获取重定向 URL 并将其传递给响应,但无法重现问题。

任何意见或建议都会有所帮助。

【问题讨论】:

    标签: java spring-mvc spring-security amazon-elb


    【解决方案1】:

    我们已经定义了自定义注销成功处理程序,如下所示

    <sec:logout success-handler-ref="logoutSuccessHandler" invalidate-session="true" delete-cookies="JSESSIONID" />
    
    • logoutSuccessHandler 类扩展了 SimpleUrlLogoutSuccessHandler 类,后者又扩展了 AbstractAuthenticationTargetUrlRequestHandler。
    • SimpleUrlLogoutSuccessHandler 和 AbstractAuthenticationTargetUrlRequestHandler 是 Spring 类的一部分
    • 在我的例子中,logoutSuccessHandler 是单例的,超类也是如此
    • 我的 logoutSuccessHandler 中的 override 方法 onLogoutSuccess 从请求中更新 DefaultTargetUrl 值并调用 super.handle 方法

      public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
          Authentication authentication) throws IOException, ServletException {
      
      super.setDefaultTargetUrl(request.getParameter("redirectUrl"));
      
      super.onLogoutSuccess(request, response, authentication);
      

      }

    DefaultTargetUrl 是 AbstractAuthenticationTargetUrlRequestHandler.class 的实例变量。

    在我的问题场景中,两个用户(USER1、USER2)都在同一个实例中处理/处理,并且同时收到了请求。由于自定义处理程序,弹簧组件是单例的,并且上述 2 个步骤不是原子的,因此线程(t01)有可能覆盖另一个线程(t02)设置的 DefaultTargetUrl。

    【讨论】:

      猜你喜欢
      • 2021-09-07
      • 2012-02-10
      • 2017-11-22
      • 2010-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-09
      • 2011-01-12
      相关资源
      最近更新 更多