我有一个tomcat应用服务器是在nginx后面。SSL在nginx上终止。部署在tomcat上的Spring web-mvc应用程序应该在JSESSIONID上设置安全标志。如果spring有一些自动检测功能就好了,这样我就不用在开发过程中因为没有SSL而烦恼了。
是否有办法告诉spring自动设置flag ?
我使用JavaConfig来设置应用程序,并使用Maven来创建可部署的war文件。
我已经检查过了,但这看起来有些丑陋和静态:集& # 39;安全# 39;标记JSESSION id cookie
当你使用spring-session时,例如在redis中持久化你的会话,这确实是自动完成的。cookie由org.springframework.session.web.http.CookieHttpSessionStrategy
创建,CookieHttpSessionStrategy#createSessionCookie
检查请求是否来自HTTPS并相应地设置安全:
sessionCookie.setSecure(request.isSecure());
如果不使用spring-session,则可以使用ServletContextInitializer
配置安全cookie。使用应用程序属性,根据配置文件将其设置为true/false。
@Bean
public ServletContextInitializer servletContextInitializer(@Value("${secure.cookie}") boolean secure) {
return new ServletContextInitializer() {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.getSessionCookieConfig().setSecure(secure);
}
};
}
应用程序。属性(当配置文件'prod'不活跃时在dev中使用):
secure.cookie=false
application-prod。属性(仅在配置文件'prod'激活时使用,覆盖application.properties中的值):
secure.cookie=false
在prod服务器上启动应用程序:
--spring.profiles.active=prod
听起来有点费力,如果你到目前为止还没有使用过配置文件,但你很可能需要一个prod环境的配置文件,所以它真的很值得。
如果您正在使用Spring Boot,那么有一个简单的解决方案。只需在application.properties
中设置以下属性:
server.servlet.session.cookie.secure=true
来源:Spring docs -附录A.常用应用程序属性
如果你有一些使用HTTPS的环境和一些没有HTTPS的环境,你需要在没有HTTPS的配置文件中将其设置为false。
。Yml只需添加
server:
session:
cookie:
secure: true
在nginx作为ssl终端后,这不是一项简单的任务:安全连接必须由nginx头检测(X-Forwarded-Proto: https
,参见使用转发头)
但它很容易解决nginx配置:
if ($scheme = http) {
return 301 https://$http_host$request_uri;
}
proxy_cookie_path / "/; secure";
我们有一个Spring Boot 2.3应用程序,它在NGINX和Tomcat之间使用HTTPS和HTTP。
即使有这个Spring属性设置:
server:
servlet:
session:
cookie:
secure: true
…当通过HTTP访问应用程序时,Secure
标志是而不是在JSESSIONID cookie上设置。你可以通过在本地运行应用程序并使用HTTP vs HTTP直接访问Tomcat来测试。
我发现添加这个到配置中设置了HTTP和HTTPS的安全标志,这解决了我们使用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);
}
};
}
添加另一个选项
你可以使用ServletContextInitializer来设置安全cookie和http only标志
@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);
}
};
}
它对我有用
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);
}
}