tomcat中LegacyCookieProcessor/Rfc6265CookieProcessor一个有双引号,一个domain不能加“.“号,终极解决方案

本文介绍了解决跨域Cookie问题的方法,特别是在使用Tomcat时如何配置以支持子域名访问主域名Cookie,包括修改LegacyCookieProcessor和Rfc6265CookieProcessor。

背景

后台将一个token以httpOnly方式写入了浏览器的cookie,在不设置cookie domain的方式下,cookie只能在本域名中使用,例如:

  • cookie的domain为"xxx.com",在子域名"yy.xxx.com"下是无法自动带入的
  • 因为安全问题设置了httpOnly,script是无法获取这种cookie来带到子域名写入的

而真实场景中,我们常常会用多域名保证主站的稳定访问;子域名用于文件上传,如果子域名无法带入主域名cookie,将无法确认上传者身份。

解决过程

通过查阅以下资料得知,tomcat随着版本的变迁,cookie的处理做过多次更新,最新的tomcat使用的是Rfc6265CookieProcessor,它使用的是白名单的方式来进行cookie的写入,中文是无法写入的,如果有中文可以使用base64编码后,再进行写入。
Tomcat中LegacyCookieProcessor与Rfc6265CookieProcessor)

这些都没有问题,使用Rfc6265CookieProcessor处理cookie的时候,domain设置有了要求,以前使用LegacyCookieProcessor是不要求domain的第一个字符的,现在要求第一个字符不能是.或者-,如果以.开头则无法写入,比如.xxx.com写入会报错,而写入xx.com则没问题。

而以前的浏览器中,如果domain设置为了.xxx.com,则子域名可以自动带入主域名的cookie。既然如此,我就按大家说的办,用以下办法设置tomcat使用LegacyCookieProcessor解析器

传统Tomcat

在cont/context.xml中,加入

<Context>
    <CookieProcessor className="org.apache.tomcat.util.http.LegacyCookieProcessor" />
</Context>

springboot

@Configuration
public class CookieConfigSupport {

    /**
     * Solve the problem:
     * There was an unexpected error (type=Internal Server Error, status=500).
     * An invalid domain [.xxx.com] was specified for this cookie
     *
     * @return
     */
    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> cookieProcessorCustomizer() {
        return (factory) -> factory.addContextCustomizers(
                (context) -> context.setCookieProcessor(new LegacyCookieProcessor()));
    }

}

一个瑕疵

我按照这么设置后,确实domain能加.了,子域名cookie也能带过来了,因为我的cookie经过了base64编码,发现cookie的值被加了双引号,没改之前没我是没有双引号的,于是我又花了一天的时间做了以下测试:

  • 双引号使用LegacyCookieProcessor/Rfc6265CookieProcessor解析器处理cookie,都能得到正确的值。
  • 无引号下生成的cookie,使用LegacyCookieProcessor/Rfc6265CookieProcessor解析器处理cookie,也能得到正确的值。

有网友会问了,你这不是讲废话么?既然都没有问题,那就用旧的解析器就好了~

但我是一个不信邪的人,遇到这种问题,就想办法去处理一下

小插曲

有资料说,在tomcat启动过程中,设置如下参数:

        System.setProperty("org.apache.tomcat.util.cookies.invalidSpecial", "false");
        System.setProperty("org.apache.tomcat.util.http.ServerCookie.ALLOW_EQUALS_IN_VALUE", "true");
        System.setProperty("org.apache.tomcat.util.http.ServerCookie.ALLOW_HTTP_SEPARATORS_IN_V0", "true");
        System.setProperty("org.apache.tomcat.util.http.ServerCookie.ALLOW_HTTP_SEPARATORS_IN_V1", "true");

可以解决引号问题,我试了,在我的环境下是不行的,可能适用于比较旧版本的tomcat

LegacyCookieProcessor

于是我把目光转到这个类上,我把这个类copy出来,将CookieConfigSupport中的处理器换成自己的。把以下代码中的'='去掉

    private static final char[] HTTP_SEPARATORS = new char[] {
            '\t', ' ', '\"', '(', ')', ',', ':', ';', '<', '>', '?', '@', '=',
            '[', '\\', ']', '{', '}' };

发现写cookie的时候果然去掉了引号,但悲剧是在这种解析器模式下,我的cookie无法正常读取了。
在此问题耗了一整天,薅掉了好些头发,也未解决,主要是水平有限在parseCookieHeader方法上浪费了不少时间,cookie的解析还包含了其他tomcat的代码,我可不想那么多

Rfc6265CookieProcessor

终于在第二天的时候灵光一闪,既然可以改LegacyCookieProcessor类,是否也可以改Rfc6265CookieProcessor,让其支持加'.'的domain不就好了,说干就干,看了一下源代码,一下就被以下代码吸引住了。

 static {
    for (char c = '0';c <= '9'; c++) {
        domainValid.set(c);
    }
    for (char c = 'a'; c <= 'z'; c++) {
        domainValid.set(c);
    }
    for (char c = 'A'; c <= 'Z'; c++) {
        domainValid.set(c);
    }
    domainValid.set('.');
    domainValid.set('-');
}

看这字面意思,就是domain相关的验证,还有set(“.”),八九不离十,连蒙带骗;把这个给注释了,调试,出现如下错误:

rfc6265CookieProcessor.invalidDomain  error

后续发现可能是因为我把文件中jar中移了出来,他找不到原来的properties,直接把这个properties的key给报了出来,反正就是有错误了。

再反复看、调试了一下代码,发现Rfc6265CookieProcessor使用的白名单机制,我把'.'去掉后,白名单中无法验证了。就直接报错了。于是继续往下看第219/220行,看这个注释,我就知道应该没有问题了,于是我做了如下修改

	// labels must start with a letter or number
    // 修改前 if ((prev == '.' || prev == -1) && (cur == '.' || cur == '-')) {
    if ( prev == -1 && cur == '-') {

最后:

  1. 将注释还原
  2. 将220注释的代码,改为上面的代码
  3. 引号和domain验证的问题解决

总结

  1. Rfc6265CookieProcessor实现了rfc6265相关的http cookie的规范,使用了更严格的字符和domain校验cookie的合法性
  2. 为什么一定要使用加'.'的方式来设置cookie,因为规范是一个事情,现实是另外一个事情,现实是你无法知道你的用户使用的浏览器是什么年代的,是否符合最新的http规范,如果符合的话,是不需要通过设置domain加'.'的方式允许子域名访问主域名的cookie的。
  3. 既然旧的解析器,并不会报错,为什么要去改Rfc6265CookieProcessor源码,两个原因:
    • cookie继承原来的书写方式,避免在生产环境中产生未知的影响,因为生产环境中不只有java
    • 使用Rfc6265CookieProcessor好处是沿用了白名单机制,只破坏了'.'的验证方式,从代码改动上来说,负担是比较小的
  4. 规范与现实总是存在差距,既然不可调和,那就解决它
<think>嗯,用户遇到了Java中的NoClassDefFoundError错误,涉及TomcatRfc6265CookieProcessor以及Cookie解析的问题。我需要先理解这个错误的原因。NoClassDefFoundError通常表示在编译时类存在,但运行时找不到。这可能是因为依赖缺失或类路径配置问题。 用户提到TomcatRfc6265CookieProcessor,这让我想到Tomcat处理Cookie的方式。Tomcat 8.5之后默认使用Rfc6265CookieProcessor,而旧版本可能使用LegacyCookieProcessor。如果项目升级了Tomcat版本,或者依赖的库不兼容新处理器,可能会导致类找不到的错误。 首先,检查Tomcat的版本。如果用户使用的是Tomcat 8.5或更高版本,可能需要确认是否缺少相关的依赖。Rfc6265CookieProcessor属于Tomcat的内置类,但有时候如果类载器配置不正确,或者某些模块被排除,可能导致问题。例如,使用JDK9及以上版本时模块化系统可能限制了类的访问,需要检查模块路径配置。 另外,用户可能在配置文件中指定了Cookie处理器。查看context.xml或web.xml中的配置,是否错误地引用了不存在的类。例如,是否错误配置了CookieProcessor属性,或者拼写错误导致类名不正确。 解决方案可能包括:1)检查Tomcat的配置,确保正确使用LegacyCookieProcessorRfc6265CookieProcessor;2)确认Tomcat的lib目录下有相关的jar包,如tomcat-util.jar;3)在模块化项目中,添必要的模块依赖,如使用--add-exports参数;4)清理项目并重新构建,确保依赖正确。 需要提醒用户注意版本兼容性,特别是在升级Tomcat或JDK时,依赖关系可能发生变化。同时,建议用户检查项目的构建路径,确保所有Tomcat相关的库都被正确包含,避免遗漏。</think>### Java NoClassDefFoundError: Rfc6265CookieProcessor 解决方案 #### 问题定位 该错误通常由以下原因引发: 1. **Tomcat版本不兼容**:Rfc6265CookieProcessorTomcat 8.5开始作为默认Cookie处理器[^1] 2. **模块化依赖缺失**:JDK9+模块系统可能限制对`org.apache.tomcat.util.http.parser`包的访问 3. **类载器冲突**:Web应用未正确继承Tomcat的lib库 #### 分步解决方案 1. **配置Tomcat Cookie处理器** 在`conf/context.xml`中添: ```xml <Context> <CookieProcessor className="org.apache.tomcat.util.http.LegacyCookieProcessor" /> </Context> ``` 或显式指定RFC6265处理器: ```xml <CookieProcessor className="org.apache.tomcat.util.http.Rfc6265CookieProcessor" /> ``` 2. **检查JDK模块配置(JDK9+)** ```bash # 添模块访问权限 --add-exports=java.base/org.apache.tomcat.util.http.parser=ALL-UNNAMED ``` 验证模块包含情况: ```bash jmod list java.base.jmod | grep CookieProcessor ``` 3. **验证库依赖** ```bash # 检查Tomcat lib目录是否包含 ls $CATALINA_HOME/lib/tomcat-util*.jar ``` 确保WEB-INF/lib不包含冲突的旧版本tomcat-util 4. **清理构建环境** ```bash mvn clean install -U # Maven项目 gradle clean build --refresh-dependencies # Gradle项目 ``` #### 进阶排查 - **类载顺序**:在`catalina.properties`中检查: ```properties tomcat.util.scan.StandardJarScanFilter.jarsToScan= ``` - **OSGi环境**:需显式导出包: ```java Export-Package: org.apache.tomcat.util.http.parser ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值