用Spring Security控制会话
最后修改:2020年8月15日
1.概述
在本文中,我们将说明如何做到这一点Spring Security允许我们控制我们的HTTP会话。
这种控制的范围从会话超时到启用并发会话和其他高级安全配置。
进一步阅读:
2.会话是什么时候创建的?
我们可以在创建会话时准确控制,以及Spring Security如何与之交互:
- 总是- 如果尚不存在,将始终创建会话
- ifRequired- 只有在需要时才会进行会话(默认的)
- 从来没有- 框架永远不会创建会话本身,但如果它已经存在,它将使用一个
- 无状态的- 春季安全不会创建或使用会话
... http>
Java配置:
@Override protected void configure(HttpSecurity http) throws Exception {http. sessionmanagement () .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)}
了解这一点非常重要此配置仅控制春季安全性的方式-不是整个应用程序。如果我们指示Spring Security不创建会话,它可能不会创建,但我们的应用程序可以!
默认,Spring Security将在需要时创建一个会话——这是……ifRequired“。
为一个更无状态的应用程序, 这 ”从来没有“选项将确保春季安全本身不会创建任何会话;但是,如果应用程序创建一个,则Spring Security将利用它。
最后,最严格的会话创作选项 - “无状态的——是一个保证应用程序根本不会创建任何会话。
这是介绍了在Spring 3.1中,将有效地跳过Spring Security过滤器链的部分——主要是会话相关的部分,比如HttpSessionSecurityContextRepository,SessionManagementFilter.,RequestCacheFilter.。
这些更严格的控制机制直接意味着不使用饼干所以每个请求都需要重新认证。这种无状态架构与REST API和他们的无状态约束效果很好。它们也适用于身份验证机制,如基本和摘要认证。
3.在引擎盖下
在执行身份验证过程之前,Spring Security将运行一个过滤器,负责在请求之间存储安全上下文SecurityContextPersistenceFilter。上下文将根据策略存储 -HttpSessionSecurityContextRepository默认 - 使用HTTP会话作为存储。
对严格的create-session =“无状态”属性,则此策略将被另一个-替换NullSecurityContextRepository- - -不会创建或使用任何会话保持上下文。
4.并发会话控制
当用户已经经过身份验证的用户尝试再次验证,应用程序可以以几种方式之一处理该事件。它可以使用户的活动会话无效并使用新会话再次对用户进行身份验证,或允许两次会话同时存在。
启用并发的第一步会话控制控件中添加以下侦听器web . xml:
org.springframework.security.web.session. httpessioneventpublisher . org.springframework.security.web.session. httpessioneventpublisher
或将其定义为豆 - 如下:
@Bean公共httpessioneventpublisher httpessioneventpublisher(){返回新的httpessioneventpublisher ();}
必须确保Spring Security会话注册表是必不可少的当会话被销毁时通知。
启用允许同一个用户进行多个并发会话的场景<会话管理>元素应该在XML配置中使用:
session-management> http>
或者,通过Java配置:
@Override保护的void配置(Httpsecurity HTTP)抛出异常{http.sessionManagement()。MaximumingSessions(2)}
5.会话超时
5.1。会话超时处理
会话超时后,如果用户发送一个请求与过期会话ID,它们将被重定向到一个可通过命名空间配置的URL:
session-management>
同样,如果用户向未到期的会话ID发送请求,但完全是无效的,它们也将被重定向到可配置的URL:
<会话管理invalid-session-url = " / invalidSession.html " >…< /会话管理>
对应的Java配置:
http.sessionmanagement().expiredurel(“/ sessionexpired.html”).InvalidSessionUll(“/ InvalidSession.html”);
5.2。使用Spring Boot配置会话超时
我们可以使用属性轻松地配置嵌入式服务器的会话超时值:
server.servlet.session.timeout = 15米
如果我们未指定持续时间单位,Spring将假设它是秒。
简而言之,通过这种配置,在不活动15分钟后,会议将过期。这段时间后的会话被视为无效。
如果我们将项目配置为使用Tomcat,我们必须记住,它只支持会话超时的微小精度,至少一分钟。这意味着如果我们指定超时值170年代例如,它将导致2分钟超时。
最后,重要的是要提及即使春季会议为此目的支持类似的财产(spring.session.timeout),如果没有指定,那么自动配置将回退到我们第一次提到的属性的值。
6.防止使用URL参数进行会话跟踪
在URL中曝光会话信息是一种不断增长的安全风险(从2007年的地方7到2013年在OWASP前10名列表中放置2。
从Spring 3.0开始的URL重写逻辑,该逻辑将附加JSessionid.现在可以通过设置disable-url-rewriting = " true "在里面
或者,从Servlet 3.0开始,会话跟踪机制也可以在web.xml:
cookie tracking-mode> session-config>
和以编程方式:
servletContext.setSessionTrackingModes (EnumSet.of (SessionTrackingMode.COOKIE));
这选择存储在哪里JSESSIONID-在cookie或URL参数中。
7.会话固定保护与弹簧安全
该框架通过配置当用户试图再次验证时,现有会话会发生什么来保护用户免受典型的会话固定攻击:
<会话管理session-fixation-protection = " migrateSession " >…
对应的Java配置:
http.sessionmanagement().sessionfixation()。迁移()
默认情况下,Spring Security启用了这个保护("迁移“) - 在身份验证上创建了一个新的HTTP会话,旧的HTTP会话无效,旧会话的属性被复制。
如果这不是所需的行为,则提供另外两个选项:
- 当“没有任何“已设置,原始会话不会无效
- 当“newsession.“已设置,将创建一个干净的会话,而不会复制旧会话的任何属性
8。安全会话Cookie
接下来,我们将讨论如何保护我们的会话cookie。
我们可以使用httpOnly和安全保护我们的会话cookie的标志:
- httponly:如果为true,则浏览器脚本将无法访问cookie
- 安全:如果是true那么cookie将仅通过https连接发送
我们可以为我们的会话饼干设置这些标志web . xml:
1 true true
自Java Servlet 3以来,此配置选项可用。默认情况下,http是是真实的安全是假的。
让我们看看相应的Java配置:
公共类MainWebAppInitializer实现WHApApplicationInitializer {@override public void onstartup(servletcontext sc)rentrows servletexception {// ... sc.getsessioncookieconfig()。sethttponly(true);sc.getSessionCookieConfig()。SeteCure(True);}}
如果我们正在使用春令生启动,我们可以在我们的中设置这些标志application.properties:
server.servlet.session.cookie.http-only = true server.servlet.session.cookie.secure = true
最后,我们也可以通过使用a手动实现这一目标筛选:
公共类SessionFilter实现过滤器{@override公共void dofilter(servletrequest请求,servletResponse响应,FilterChain链)抛出IoException,servletException {httpservletRequest req =(httpservletRequest)请求;httpservletresponse res =(httpservletresponse)响应;cookie [] AllCookies = req.getcookies();if(AllCookies!= null){cookie会话= arrays.stream(AllCookies).filter(x - > x.getname()。等于(“jsessionid”)).findfirst()。orelse(null);if(会话!= null){session.sethttponly(true);session.setsecure(真实);res.addcookie(会议);链条.Dofilter(REQ,RES);}}
9.与会话一起工作
9.1。会话作用域的bean
可以使用bean定义会话只要在web-Context中声明的bean上使用@Scope注释:
@component @scope(“session”)公共类foo {..}
或使用XML:
< bean id = " foo "范围=“会话”/ >
然后,可以简单地注入另一个bean:
@autowired私人foo thefoo;
Spring将新bean绑定到HTTP Session的生命周期。
9.2。将原始会话注入控制器
原始的HTTP会话也可以直接注入到控制器方法:
@RequestMapping(.) public void fomethod (HttpSession session) {session. setattribute (Constants. properties);FOO,新的FOO ());/ /……Foo Foo = (Foo) session.getAttribute(Constants.FOO);}
9.3。获取原始会话
当前的HTTP会话也可以通过生Servlet API:
ServletRequestAttributes attr = (ServletRequestAttributes) requestcontexthholder . currentrequestattributes ();HttpSession会话= attr.getRequest () .getSession(真正的);// true ==允许创建
10.结论
在本文中,我们讨论了具有Spring Security的管理会话。此外,弹簧参考包含一个非常好的会议管理常见问题。
一如既往,本文中提供的代码可用在github上。这是一个基于Maven的项目,因此应该易于导入和运行。