【问题标题】:Forcing Tomcat to use secure JSESSIONID cookie over http强制 Tomcat 通过 http 使用安全的 JSESSIONID cookie
【发布时间】:2013-02-06 00:25:27
【问题描述】:

有没有办法配置 Tomcat 7 以在所有情况下创建带有安全标志的 JSESSIONID cookie?

仅当通过 https 建立连接时,通常的配置会导致 Tomcat 使用安全标志标记会话 cookie。但是在我的生产场景中,Tomcat 位于一个反向代理/负载均衡器后面,它处理(和终止)https 连接并通过 http 联系 tomcat。

我能否以某种方式强制使用 Tomcat 的会话 cookie 上的安全标志,即使连接是通过纯 http 进行的?

【问题讨论】:

    标签: java security tomcat session-cookies


    【解决方案1】:

    ServletContext.getSessionCookieConfig().setSecure(true)

    【讨论】:

    【解决方案2】:

    最后,与我最初的测试相反,web.xml 解决方案在 Tomcat 7 上为我工作。

    例如我将此 sn-p 添加到 web.xml 中,即使反向代理通过纯 HTTP 联系 tomcat,它也会将会话 cookie 标记为安全。

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

    【讨论】:

      【解决方案3】:

      另一种方法,类似于 Mark 的方法,是使用 SessionCookieConfig,但将其设置在 JNDI 配置的上下文侦听器中:

      代码:

      import javax.naming.Context;
      import javax.naming.InitialContext;
      import javax.naming.NamingException;
      import javax.servlet.ServletContextEvent;
      import javax.servlet.ServletContextListener;
      import javax.servlet.SessionCookieConfig;
      
      
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      
      
      public class JndiSessionCookieConfigListener implements ServletContextListener {
          private static final Logger logger = LoggerFactory.getLogger( JndiSessionCookieConfigListener.class );
      
          private volatile Context jndiSessionCookieConfig;
          private volatile SessionCookieConfig sessionCookieConfig;
      
          @Override
          public void contextInitialized( ServletContextEvent sce ) {
              String listenerName = getClass().getSimpleName();
              try {
                  logger.info( "JNDI override session cookie config found for {}", listenerName );
                  jndiSessionCookieConfig = (Context) new InitialContext().lookup(
                          "java:comp/env/" + listenerName );
              }
              catch ( NamingException e ) {
                  logger.info( "No JNDI override session cookie config found for {}", listenerName );
              }
      
              sessionCookieConfig = sce.getServletContext().getSessionCookieConfig();
      
              String comment = getString( "comment" );
              if ( comment != null ) {
                  logger.debug( "\t[comment]: [{}]", comment );
                  sessionCookieConfig.setComment( comment );
              }
      
              String domain = getString( "domain" );
              if ( domain != null ) {
                  logger.debug( "\t[domain]: [{}]", domain );
                  sessionCookieConfig.setDomain( domain );
              }
      
              Boolean httpOnly = getBoolean( "http-only" );
              if ( httpOnly == null ) {
                  sessionCookieConfig.setHttpOnly( true );
              }
              else {
                  logger.debug( "\t[http-only]: [{}]", httpOnly );
                  sessionCookieConfig.setHttpOnly( httpOnly );
              }
      
              Integer maxAge = getInteger( "max-age" );
              if ( maxAge != null ) {
                  sessionCookieConfig.setMaxAge( maxAge );
              }
      
              String name = getString( "name" );
              if ( name != null ) {
                  logger.debug( "\t[name]: [{}]", name );
                  sessionCookieConfig.setName( name );
              }
      
              String path = getString( "path" );
              if ( path != null ) {
                  logger.debug( "\t[path]: [{}]", path );
                  sessionCookieConfig.setPath( path );
              }
      
              Boolean secure = getBoolean( "secure" );
              if ( secure == null ) {
                  sessionCookieConfig.setSecure( true );
              }
              else {
                  logger.debug( "\t[secure]: [{}]", secure );
                  sessionCookieConfig.setSecure( secure );
              }
          }
      
          @Override
          public void contextDestroyed( ServletContextEvent sce ) {
          }
      
          private Boolean getBoolean( String name ) {
              Object value;
              try {
                  value = jndiSessionCookieConfig.lookup( name );
                  if ( value instanceof Boolean ) {
                      return (Boolean)value;
                  }
                  else {
                      return Boolean.valueOf( value.toString() );
                  }
              }
              catch ( NamingException e ) {
                  return null;
              }
          }
      
          private Integer getInteger( String name ) {
              Object value;
              try {
                  value = jndiSessionCookieConfig.lookup( name );
                  if ( value instanceof Integer ) {
                      return (Integer)value;
                  }
                  else {
                      return Integer.valueOf( value.toString() );
                  }
              }
              catch ( NamingException e ) {
                  return null;
              }
          }
      
          private String getString( String name ) {
              Object value;
              try {
                  value = jndiSessionCookieConfig.lookup( name );
                  return value.toString();
              }
              catch ( NamingException e ) {
                  return null;
              }
          }
      }
      

      在 web.xml 中:

      ...
        <listener>
          <listener-class>
            org.mitre.caasd.servlet.init.JndiSessionCookieConfigListener
          </listener-class>
        </listener>
      ...
      

      在您的 context.xml 中:

      ...
      <Environment name="JndiSessionCookieConfigListener/secure"
        type="java.lang.String"
        override="false"
        value="true" />
      ...
      

      这允许您在运行时设置所有会话 cookie 配置在部署环境中。因此,您可以使用相同的 webapp(war 文件)在本地进行开发(您不会有 https)和在生产环境中总是需要 https。

      注意,OWASP documentation中提到了这种方法

      【讨论】:

      • 在生产中,您总是需要 https。 并非总是如此。是的,您希望客户端连接始终通过 HTTPS,但不是必需的 tomcat。在大多数情况下,tomcat 将位于反向代理之后 - 代理和 tomcat 之间的连接不会是 HTTPS。
      猜你喜欢
      • 2015-05-28
      • 1970-01-01
      • 2017-11-24
      • 2014-06-11
      • 2020-11-16
      • 2013-08-02
      • 2011-06-23
      • 2012-06-30
      相关资源
      最近更新 更多