Forcing Tomcat to use secure JSESSIONID cookie over http

本秂侑毒 提交于 2019-11-28 06:21:33

In the end, contrary to my initial tests, web.xml solution worked for me on Tomcat 7.

E.g. I added this snippet to web.xml and it marks session cookie as secure even when reverse proxy contacts tomcat over plain HTTP.

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

ServletContext.getSessionCookieConfig().setSecure(true)

Another approach, similar to Mark's, would be to use the SessionCookieConfig, but set it in a context listener from JNDI configuration:

The code:

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;
        }
    }
}

Inside web.xml:

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

In your context.xml:

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

This allows you to set all the session cookie configurations at runtime in the deployment environment. Thus, you could use the same webapp (war file) to do development locally (where you would not have https) and in production where you would ALWAYS want https.

Note, this approach is mentioned in the OWASP documentation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!