我目前正在构建Spring应用程序(2.3.1,但使用Security保护的版本2.1.7和2.1.5也注意到了以下问题)。我主要使用默认设置(例如嵌入式Tomcat、嵌入式H2数据库、Spring )。我使用以下代码对允许的POST映射执行一些自定义身份验证:
UsernamePasswordAuthenticationToken authentication = ...;
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(authentication);这个很好用。由于我想在学生考试中使用它,所以我希望持久化认证会话,所以如果服务器软件因某种原因崩溃或停机,当服务器再次出现时,没有人需要重新验证。
为此,我使用了Spring会话JDBC。我将以下依赖项添加到我的pom.xml中
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-jdbc</artifactId>
</dependency>和我的application.properties的下面一行
spring.session.store-type=jdbc当我在本地测试时,这一切都很好。我看到会话出现在我的数据库中,一切都很好。然而,在实践中,应用程序是从iframe启动的:学习管理系统执行LTI启动,这是一个POST请求,响应在iframe中结束。当我尝试进行测试部署时,我收到了一个403错误,请求没有经过身份验证。在经历了令人沮丧的一天调试之后,我终于能够将这个问题归结为这样一个事实:将spring-session-jdbc添加到我的项目中会导致web应用程序在iframe的每个请求上发送一个新的会话ID cookie。如果我在没有iframe的情况下重复相同的请求,那么相同的应用程序可以正常工作。如果我移除spring-session-jdbc依赖项,应用程序在iframe中也可以正常工作。
如果在iframe中执行身份验证,在Security调试日志中可以看到以下内容(exec-1是成功身份验证发生的地方,exec-2是iframe在被exec-1请求重定向后执行的请求):
2020-06-24 22:14:02.015 DEBUG 7474 --- [nio-8031-exec-1] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@671fa7ec
2020-06-24 22:14:02.015 DEBUG 7474 --- [nio-8031-exec-1] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2020-06-24 22:14:02.063 DEBUG 7474 --- [nio-8031-exec-1] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2020-06-24 22:14:02.113 DEBUG 7474 --- [nio-8031-exec-2] o.s.security.web.FilterChainProxy : /launch/development at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-06-24 22:14:02.113 DEBUG 7474 --- [nio-8031-exec-2] o.s.security.web.FilterChainProxy : /launch/development at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-06-24 22:14:02.114 DEBUG 7474 --- [nio-8031-exec-2] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2020-06-24 22:14:02.114 DEBUG 7474 --- [nio-8031-exec-2] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.当我在常规浏览器窗口中使用相同运行的应用程序执行相同请求时,Security调试日志显示如下:
2020-06-24 22:18:10.518 DEBUG 7474 --- [nio-8031-exec-5] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@671fa7ec
2020-06-24 22:18:10.518 DEBUG 7474 --- [nio-8031-exec-5] w.c.HttpSessionSecurityContextRepository : SecurityContext 'org.springframework.security.core.context.SecurityContextImpl@e1239cdc: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@e1239cdc: Principal: testuserid; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_INSTRUCTOR' stored to HttpSession: 'org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper$HttpSessionWrapper@66670854
2020-06-24 22:18:10.536 DEBUG 7474 --- [nio-8031-exec-5] o.s.s.w.a.ExceptionTranslationFilter : Chain processed normally
2020-06-24 22:18:10.536 DEBUG 7474 --- [nio-8031-exec-5] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2020-06-24 22:18:10.590 DEBUG 7474 --- [nio-8031-exec-6] o.s.security.web.FilterChainProxy : /home at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-06-24 22:18:10.591 DEBUG 7474 --- [nio-8031-exec-6] o.s.security.web.FilterChainProxy : /home at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-06-24 22:18:10.592 DEBUG 7474 --- [nio-8031-exec-6] w.c.HttpSessionSecurityContextRepository : Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl@82a4fa0f: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@82a4fa0f: Principal: testuserid; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_INSTRUCTOR'对我来说,这似乎很奇怪:如果这纯粹是一个浏览器问题,那么我是否使用spring-session-jdbc并不重要。如果spring-session-jdbc如何存储我的身份验证存在问题,那么它是否发生在iframe中也不重要。这里有什么东西我遗漏了吗?我被虫子绊倒了吗?
我可以尝试一种解决方法,在iframe中使用一些javascript,让POST出现在一个空白选项卡中,但感觉很难看。
发布于 2020-06-25 09:07:04
总的来说,我建议你不要在iframe中使用你的应用程序。
这会带来安全风险,您可以在this answer中更多地了解这些风险。
现在来解释一下你所看到的行为。
Security使用Session cookie来存储用户的会话。
cookie与域相关联,因此,例如,如果存在与域stackoverflow.com相关联的cookie,那么该cookie将包含在对stackoverlow.com的任何请求中。
为了控制这种行为,cookie还具有一个名为SameSite的属性。
SameSite attribute可以有3个值,None、Lax或Strict。
当值为None时,它的行为如上文所述(包括在所有请求中)。
当值为Lax时,cookie将只包含在顶级导航GET请求中。
当包含Spring会话依赖项时,默认情况下将Session cookie SameSite属性设置为Lax。
因为在iframe中呈现应用程序不是顶级导航,所以Session cookie不包含在对iframe的请求中,并且应用程序无法知道用户已被登录。
您可以使用Session显式地将SameSite属性设置为None。
同样,我要提醒您不要这样做,因为它会使您的应用程序容易受到CSRF和点击劫持攻击的攻击。
如果在考虑了安全性影响之后,您认为有必要将SameSite属性设置为None,则可以通过在依赖项中包含Spring会话并创建custom CookieSerializer来做到这一点。
https://stackoverflow.com/questions/62563620
复制相似问题