【发布时间】:2017-08-10 13:27:48
【问题描述】:
我用Spring 3开发的Restful服务应用部署在Tomcat7上。我使用一个名为 Postman 的 chrome 应用来请求 REST 服务。
我在所有服务(非安全服务登录除外)之前放置了一个自定义过滤器,用于检查会话和应用程序特定的 cookie。 如果 cookie 在传入的 HttpServletRequest 中不存在或无效,则此过滤器返回 HTTP 状态:403。过滤器 (myCustomSecurityFilter) 是单例范围的。
<security:intercept-url pattern="/services/v1/login" access="permitAll()" /> <security:custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="myCustomSecurityFilter" />
我观察到在特定情况下使用旧的 HttpServletRequest。请看以下场景
案例 #1:所有请求都通过 HTTPS。
所有 cookie 都被删除并重新启动浏览器。
调用 HTTPS 服务:..\services\v1\account。由于必须在 ..\services\v1\login 之后调用此服务,因此预计会出现 403 响应。实际回复:403。 Tomcat 会创建一个新会话并返回一个 JSESSIONID。比如说,JSESSIONID_1。
- 请求 ..\services\v1\login 。预期和实际响应 200-OK。 Tomcat 会创建一个新会话并返回一个 JSESSIONID。比如说,JSESSIONID_2。 应用程序特定的 cookie 也会返回给客户端/浏览器。比如说,App_cookie_1。
- 调用除 ..\services\v1\account 之外的任何其他服务。全部成功(200)。 Cookie JSESSIONID_2、App_cookie_1 是请求发送的,收到响应后也可以观察到。 注意:这一步并不重要。可以使用或不使用此步骤来重现步骤 5。
- 请求 ..\services\v1\account。预期:200。实际:403。 当我调试上面提到的 SecurityFilter 中的 doFilter 方法收到的 HttpServletRequest 时,我看到 HttpServletRequest 包含对同一服务 ..\services\v1\account 的先前请求的旧 cookie。 即 JSESSIONID_1。没有应用程序 cookie。 我在 httpServletRequest.getCookies() 的帮助下检查了 cookie 浏览器显示 Cookie JSESSIONID_2、App_cookie_1。我确信 Tomcat 会收到 Cookie JSESSIONID_2、App_cookie_1 因为我启用了访问日志记录。 因此,是 Spring(我的代码或 Spring 框架之上的配置)将旧的 HttpServletRequest 传递给过滤器。但是怎么做?为什么?
- 请求 ..\services\v1\account。预期:200。实际:200。 Cookie JSESSIONID_2、App_cookie_1 是请求发送的,收到响应后也可以观察到。 因此,旧 cookie 仅使用一次,并且在这种情况下也仅用于同一服务(..\services\v1\account)。
Webapp 在以下情况下按预期工作(以上步骤用数字表示): 案例2:1、2、3、4、5、6。除#2(登录请求)外,所有都是 HTTPS 请求。如果 #2 是 HTTP 请求,则 #5 返回 200!这也是一个惊喜。 案例 3:2、3、4、5、6。 案例4:2,3,5,6。
第 4 步并不重要。可以使用或不使用此步骤来重现步骤 5。我放置这个是为了解释加载相同服务的先前请求并且对其他服务没有影响。 问题绝对不在于 ..\services\v1\account。因为我刚刚使用了这个服务。应用程序中的任何安全服务都可以重复案例 1。
我尝试使用 newSessio、migrateSession 选项管理我的会话。
<security:session-management session-fixation-protection="newSession">
<security:concurrency-control max-sessions="1" />
</security:session-management>
感谢您阅读我的问题。如果您能提供一些指示,那就太好了。 如果我不清楚,请告诉我。
【问题讨论】:
-
在对 Spring 过滤器链进行了更多调试之后。我注意到 HttpSessionRequestCache 创建的 savedRequest 有旧的 cookie。这个保存的会话是根据请求的会话属性 SPRING_SECURITY_SAVED_REQUEST 准备的。这只是一个发现,还没有找到解决方案:(
-
由于我无法找到并解决 Spring 框架从会话存储库加载旧会话的行为,我正在使用以下解决方法(可以称为先发制人的措施)来阻止上述情况的发生。先发制人的措施:我将所有 403 响应路由到我的 /v1/access-denied 服务,然后在“access-denied”中使会话无效。这将从 SpringSessionRepository 中删除会话,并防止稍后在身份验证后加载此会话。
标签: spring session cookies session-cookies session-management