强制Tomcat通过http使用安全的JSESSIONID cookie

i34xakig  于 2023-06-23  发布在  其他
关注(0)|答案(4)|浏览(197)

是否有一种方法可以配置Tomcat 7在所有情况下创建带有安全标志的JSESSIONID cookie?
通常的配置导致Tomcat仅在通过https进行连接时才使用安全标志标记会话cookie。但是在我的生产场景中,Tomcat位于反向代理/负载均衡器的后面,后者处理(并终止)https连接并通过http与Tomcat联系。
我是否可以在Tomcat的会话cookie上强制使用安全标志,即使连接是通过普通http建立的?

yqkkidmi

yqkkidmi1#

最后,与我最初的测试相反,web.xml解决方案在Tomcat 7上适用。
例如,我将这个代码片段添加到web.xml中,它将会话cookie标记为安全,即使反向代理通过普通HTTP联系tomcat。

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

ymzxtsji2#

ServletContext.getSessionCookieConfig().setSecure(true)

krcsximq

krcsximq3#

另一种方法,与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>
...

在上下文中.xml:

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

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

  • 注意,OWASP文档中提到了这种方法 *
ff29svar

ff29svar4#

您可以执行以下操作以通过http使用安全的JSESSIONID cookie。
对于Tomcat版本:7.x/8.x/9.x
转到Tomcat--> conf文件夹打开web.xml并在session-config部分添加以下内容:

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

此外,建议启用SameSite属性。
它的目的是防止cookie被包含在跨站点请求中,以减轻不同的客户端攻击,如CSRF,XS-Leaks和XSS。
转到--> conf文件夹打开context.xml将以下行添加到文件中,位于<Context>标记下方:

<CookieProcessor className="org.apache.tomcat.util.http.Rfc6265CookieProcessor" sameSiteCookies="strict" />

现在重新启动tomcat服务器,在浏览器--> DevTools --> Application中,您可以确认更改。

相关问题