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

背景

后台将一个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. 规范与现实总是存在差距,既然不可调和,那就解决它
  • 0
    点赞
  • 0
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论

打赏作者

隔壁老易

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值