简体   繁体   English

在 spring 中自动将安全标志添加到 JSESSIONID cookie

[英]Add secure flag to JSESSIONID cookie in spring automatically

I have a tomcat application server that is behind a nginx.我有一个位于 nginx 后面的 tomcat 应用程序服务器。 SSL terminates on the nginx. SSL 在 nginx 上终止。 The Spring web-mvc application that is deployed on the tomcat should set the secure flag on the JSESSIONID.部署在 tomcat 上的 Spring web-mvc 应用程序应在 JSESSIONID 上设置安全标志。 It would be cool if spring has some automatic detection for this so I don't get bothered during development because I don't have SSL there.如果spring对此有一些自动检测会很酷,这样我就不会在开发过程中受到打扰,因为我没有SSL。

Is there a way to tell spring to set the flag automatically?有没有办法告诉spring自动设置标志?

I use JavaConfig to setup the application and use Maven to create a deployable war-file.我使用 JavaConfig 设置应用程序并使用 Maven 创建可部署的战争文件。

I have checked this already, but this looks somehow ugly and static: set 'secure' flag to JSESSION id cookie我已经检查过了,但这看起来有点丑陋和静态: 将“安全”标志设置为 JSESSION id cookie

When you use spring-session , eg to persist your session in reddis, this is indeed done automatically.当你使用spring-session时,例如在 reddis 中持久化你的会话,这确实是自动完成的。 The cookie is than created by org.springframework.session.web.http.CookieHttpSessionStrategy which in CookieHttpSessionStrategy#createSessionCookie checks if the request comes via HTTPS and sets secure accordingly: cookie 是由org.springframework.session.web.http.CookieHttpSessionStrategy创建的,它在CookieHttpSessionStrategy#createSessionCookie检查请求是否来自 HTTPS 并相应地设置安全:

sessionCookie.setSecure(request.isSecure());

If you do not use spring-session, you can configure secure cookies using a ServletContextInitializer .如果使用 spring-session,则可以使用ServletContextInitializer配置安全 cookie。 Use a application property , to set it to true/false depending on a profile.使用应用程序属性,根据配置文件将其设置为真/假。

@Bean
public ServletContextInitializer servletContextInitializer(@Value("${secure.cookie}") boolean secure) {
    return new ServletContextInitializer() {

        @Override
        public void onStartup(ServletContext servletContext) throws ServletException {
            servletContext.getSessionCookieConfig().setSecure(secure);
        }
    };
}

application.properties (used in dev when profile 'prod' is not active): application.properties(在配置文件“prod”未激活时用于开发):

secure.cookie=false

application-prod.properties (only used when profile 'prod' is active, overwrites value in application.properties): application-prod.properties(仅在配置文件“prod”处于活动状态时使用,覆盖 application.properties 中的值):

secure.cookie=false

start your application on the prod server with :使用以下命令在 prod 服务器上启动您的应用程序:

--spring.profiles.active=prod

Sounds like some effort, if you have not worked with profiles so far, but you will most likely need a profile for prod environment anyway, so its really worth it.如果您到目前为止还没有使用过配置文件,这听起来像是一些努力,但无论如何您很可能需要一个用于 prod 环境的配置文件,所以它真的很值得。

If you are using Spring Boot, there is a simple solution for it.如果您使用的是 Spring Boot,则有一个简单的解决方案。 Just set the following property in your application.properties :只需在application.properties中设置以下属性:

server.servlet.session.cookie.secure=true

Source: Spring docs - Appendix A. Common application properties来源: Spring docs - 附录 A. 常见应用程序属性

If you have some environment with HTTPS and some without it, you will need to set it to false in profiles without HTTPS.如果您有一些使用 HTTPS 的环境而一些没有使用 HTTPS,则需要在没有 HTTPS 的配置文件中将其设置为 false。 Otherwise the Secure cookie is ignored.否则,安全 cookie 将被忽略。

in your application.yml just add在您的 application.yml 中添加

server:
  session:
    cookie:
      secure: true

Behind nginx as ssl terminal point it is not trivial task: secured connection must be detected by nginx header ( X-Forwarded-Proto: https , see Using the Forwarded header )在 nginx 作为 ssl 终端点之后,这不是一项简单的任务:必须通过 nginx 标头检测安全连接( X-Forwarded-Proto: https ,请参阅使用转发标头
But it is easy solved by nginx config:但是通过 nginx 配置很容易解决:

if ($scheme = http) {
    return 301 https://$http_host$request_uri;
}
proxy_cookie_path / "/; secure";

Add another option添加另一个选项

You can use a ServletContextInitializer to set secure cookie and http only flag您可以使用 ServletContextInitializer 设置安全 cookie 和仅 http 标志

@Bean
public ServletContextInitializer servletContextInitializer() {
    return new ServletContextInitializer() {
        @Override
        public void onStartup(ServletContext servletContext) throws ServletException {
            servletContext.setSessionTrackingModes(Collections.singleton(SessionTrackingMode.COOKIE));
            SessionCookieConfig sessionCookieConfig = servletContext.getSessionCookieConfig();
            sessionCookieConfig.setHttpOnly(true);
            sessionCookieConfig.setSecure(true);
        }
    };
}

It's working for me它对我有用

public class WebInitializer implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
    AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
    ctx.register(AppConfig.class);
    ctx.setServletContext(servletContext);
    Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
    servlet.addMapping("/");
    servlet.setLoadOnStartup(1);

    servletContext.setSessionTrackingModes(Collections.singleton(SessionTrackingMode.COOKIE));
    SessionCookieConfig sessionCookieConfig = servletContext.getSessionCookieConfig();
    sessionCookieConfig.setHttpOnly(true);
    sessionCookieConfig.setSecure(true);
}
}

We have a Spring Boot 2.3 app that uses HTTPS to NGINX and HTTP between NGINX and Tomcat.我们有一个 Spring Boot 2.3 应用程序,它在 NGINX 和 Tomcat 之间使用 HTTPS 到 NGINX 和 HTTP。

Even with this Spring property setting:即使使用此 Spring 属性设置:

server:
    servlet:
        session:
            cookie:
                secure: true

... the Secure flag is not being set on the JSESSIONID cookie when the app is accessed via HTTP. ...当通过 HTTP 访问应用程序时,在 JSESSIONID cookie 上设置Secure标志。 You can test this by running the app locally and hitting Tomcat directly using HTTP vs HTTP.您可以通过在本地运行应用程序并使用 HTTP 与 HTTP 直接访问 Tomcat 来测试这一点。

I found that adding this to the config sets the Secure flag for HTTP and HTTPS which fixes our issue when putting NGINX in front of Tomcat using HTTP:我发现将它添加到配置中会设置 HTTP 和 HTTPS 的 Secure 标志,这解决了使用 HTTP 将 NGINX 放在 Tomcat 前面时的问题:

/**
 * Fix for GCP... since we use HTTP internally in Kubernetes, Spring will not make JSESSIONID Secure, but this will.
 *
 * See https://www.javafixing.com/2021/11/fixed-add-secure-flag-to-jsessionid.html
 *
 * @return
 */
@Bean
public ServletContextInitializer servletContextInitializer() {
    return new ServletContextInitializer() {

        @Override
        public void onStartup(ServletContext servletContext) throws ServletException {
            servletContext.getSessionCookieConfig().setSecure(true);
        }
    };
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM