• 使用Spring Security控制会话


    1.概述

    在本文中,我们将说明Spring Security如何允许我们控制HTTP会话。此控件的范围从会话超时到启用并发会话和其他高级安全配置。

    2.会话何时创建?

    我们可以准确控制会话何时创建以及Spring Security如何与之交互:

    • always - 如果一个会话尚不存在,将始终创建一个会话
    • ifRequired - 仅在需要时创建会话(默认)
    • never - 框架永远不会创建会话本身,但如果它已经存在,它将使用一个
    • stateless - Spring Security不会创建或使用任何会话
    <http create-session="ifRequired">...</http>
    
    Java配置:
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
    }
    

    解此配置仅控制Spring Security的功能非常重要 - 而不是整个应用程序。如果我们不指示Spring Security,可能无法创建会话,但我们的应用程序可能会!

    默认情况下,Spring Security会在需要时创建会话 - 这是“ifRequired”

    对于更无状态的应用程序,“never”选项将确保Spring Security本身不会创建任何会话;但是,如果应用程序创建了一个,那么Spring Security将使用它。

    最后,最严格的会话创建选项 - “stateless” - 保证应用程序根本不会创建任何会话

    这是在Spring 3.1中引入的,它将有效地跳过部分Spring Security过滤器链。主要是会话相关的部分,如HttpSessionSecurityContextRepository,SessionManagementFilter,RequestCacheFilter

    这些更严格的控制机制直接暗示不使用cookie,所以每个请求都需要重新进行身份验证。这种无状态架构适用于REST API及其无状态约束。它们也适用于基本和摘要式身份验证等身份验证机制。

    3. Under The Hood

    在执行身份验证过程之前,Spring Security将运行一个负责在请求之间存储安全上下文的过滤器-SecurityContextPersistenceFilter。上下文将根据策略存储 - 默认情况下为HttpSessionSecurityContextRepository - 它使用HTTP会话作为存储。对于strict create-session =“stateless”属性,此策略将替换为另一个 - NullSecurityContextRepository - 并且不会创建或使用会话来保留上下文。

    4.并发会话控制

    当已经过身份验证的用户尝试再次进行身份验证时,应用程序可以通过以下几种方式之一处理该事件。它可以使用户的活动会话无效,并使用新会话再次对用户进行身份验证,或者允许两个会话同时存在

    启用并发会话控制支持的第一步是在web.xml中添加以下侦听器:

    <listener>
        <listener-class>
          org.springframework.security.web.session.HttpSessionEventPublisher
        </listener-class>
    </listener>
    

    或者将其定义为Bean - 如下所示:

    @Bean
    public HttpSessionEventPublisher httpSessionEventPublisher() {
        return new HttpSessionEventPublisher();
    }
    

    这对于确保在销毁会话时通知Spring Security会话注册表是至关重要。

    要为同一用户启用允许多个并发会话的方案,应在XML配置中使用元素:

    <http ...>
        <session-management>
            <concurrency-control max-sessions="2" />
        </session-management>
    </http>
    

    或者,通过Java配置:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement().maximumSessions(2)
    }
    

    5.会话超时

    会话超时后,如果用户发送的会话ID已过期,则会将其重定向到可通过命名空间配置的URL:

    <session-management>
        <concurrency-control expired-url="/sessionExpired.html" ... />
    </session-management>
    

    同样,如果用户发送的会话ID未过期但完全无效,则它们也会被重定向到可配置的URL:

    <session-management invalid-session-url="/invalidSession.html">
        ...
    </session-management>
    

    相应的Java配置:

    http.sessionManagement()
      .expiredUrl("/sessionExpired.html")
      .invalidSessionUrl("/invalidSession.html");
    

    6.防止使用URL参数进行会话跟踪

    在URL中公开会话信息的安全风险越来越大(从2007年的第7位到2013年在OWASP排行榜前10位的第2位)。

    从Spring 3.0开始,现在可以通过在命名空间中设置disable-url-rewriting =“true”来禁用将jsessionid附加到URL的URL重写逻辑。

    或者,从Servlet 3.0开始,也可以在web.xml中配置会话跟踪机制

    <session-config>
         <tracking-mode>COOKIE</tracking-mode>
    </session-config>
    

    编程方式

    servletContext.setSessionTrackingModes(EnumSet.of(SessionTrackingMode.COOKIE));
    

    这将选择存储JSESSIONID的位置 - 在cookie或URL参数中

    7. Spring Security的会话固定保护

    该框架通过配置在用户已有会话的情况但尝试再次进行身份验证时,提供了针对典型会话固定攻击的保护:

    <session-management session-fixation-protection="migrateSession"> ...
    

    相应的Java配置:

    http.sessionManagement()
      .sessionFixation().migrateSession()
    

    默认情况下,Spring Security启用了此保护(“migrateSession”) - 在身份验证时,会创建一个新的HTTP会话,旧的会话将失效,旧会话的属性将被复制

    如果这不是所需的行为,则可以使用其他两个选项:

    • 设置“none”时,原始会话不会失效
    • 设置“newSession”时,将创建一个干净的会话,而不会复制旧会话中的任何属性

    8.安全会话Cookie

    接下来,我们将讨论如何保护会话cookie。
    我们可以使用httpOnly和secure标签来保护我们的会话cookie

    • httpOnly:如果为true,那么浏览器脚本将无法访问cookie
    • secure:如果为true,则cookie将仅通过HTTPS连接发送

    我们可以在web.xml中为会话cookie设置这些标志:

    <session-config>
        <session-timeout>1</session-timeout>
        <cookie-config>
            <http-only>true</http-only>
            <secure>true</secure>
        </cookie-config>
    </session-config>
    

    从Java servlet 3开始,此配置选项可用。默认情况下,http-only为true且secure为false

    我们来看看相应的Java配置:

    public class MainWebAppInitializer implements WebApplicationInitializer {
        @Override
        public void onStartup(ServletContext sc) throws ServletException {
            // ...
            sc.getSessionCookieConfig().setHttpOnly(true);        
            sc.getSessionCookieConfig().setSecure(true);        
        }
    }
    

    如果我们使用Spring Boot,我们可以在application.properties中设置这些标志:

    server.servlet.session.cookie.http-only=true
    server.servlet.session.cookie.secure=true
    

    最后,我们还可以使用Filter手动实现此目的:

    public class SessionFilter implements Filter {
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
          throws IOException, ServletException {
            HttpServletRequest req = (HttpServletRequest) request;
            HttpServletResponse res = (HttpServletResponse) response;
            Cookie[] allCookies = req.getCookies();
            if (allCookies != null) {
                Cookie session = 
                  Arrays.stream(allCookies).filter(x -> x.getName().equals("JSESSIONID"))
                        .findFirst().orElse(null);
     
                if (session != null) {
                    session.setHttpOnly(true);
                    session.setSecure(true);
                    res.addCookie(session);
                }
            }
            chain.doFilter(req, res);
        }
    }
    

    9.Session使用

    9.1。 Session Scoped Beans

    只需在web-Context中,使用@Scope注释声明的bean:

    @Component
    @Scope("session")
    public class Foo { .. }
    

    或者使用XML:

    <bean id="foo" scope="session"/>
    

    然后,bean可以简单地注入另一个bean:

    @Autowired
    private Foo theFoo;
    

    Spring会将新bean绑定到HTTP Session的生命周期。

    9.2。将会话注入控制器

    原始HTTP会话也可以直接注入Controller方法:

    @RequestMapping(..)
    public void fooMethod(HttpSession session) {
        session.addAttribute(Constants.FOO, new Foo();
        //...
        Foo foo = (Foo) session.getAttribute(Constants.Foo);
    }
    

    9.3。获取会话

    当前的HTTP Session也可以通过原始Servlet API以编程方式获得:

    ServletRequestAttributes attr = (ServletRequestAttributes) 
        RequestContextHolder.currentRequestAttributes();
    HttpSession session= attr.getRequest().getSession(true); // true == allow create
    

    10.总结

    在本文中,我们讨论了使用Spring Security管理Sessions。此外,Spring Reference包含一个非常好的会话管理常见问题解答

    与往常一样,本文中提供的代码可以在Github上获得。这是一个基于Maven的项目,因此它应该很容易导入和运行。

  • 相关阅读:
    Eclipse 3.0.1插件方案(Java版) zt
    Vs2003使用时出现这个问题,正在郁闷中,网上找了好久,居然看到同样问题,马上拷贝来:)开心中
    Eclipse+Tomcat集成开发servletzt
    管理定律
    张小娴“禁果之味”
    上海主要特色医院一览表
    分布式网站数据库同步方案——sqlserver数据库同步复制,好文收藏之
    Eclipse 插件汇总(转载+不断更新) zt
    Eclipse零起步系列讲座 zt
    结婚这件事
  • 原文地址:https://www.cnblogs.com/xjknight/p/10897849.html
Copyright © 2020-2023  润新知