0%

【踩坑】An invalid domain [.xxx.com] was specified for this cookie

Tomcat 8.5 在设置 Cookie 时,会对 Cookie 的域名进行强校验,在以前的版本 CookieProcessor 有着不同实现,于是探究了在升级 Tomcat 版本后会出现的问题和解决方案。

问题发生

1
2
3
4
Cookie cookie = new Cookie("xxx", "texxxst");
cookie.setDomain(".xxx.com");
cookie.setPath("/");
resp.addCookie(cookie);

在系统中有这么一段代码,在 Tomcat8.0 的机器上安然无恙的运行着,今天升级了若干台机器到了 Tomcat8.5 后,系统开始不断打出以下异常:

1
2
3
4
5
java.lang.IllegalArgumentException: An invalid domain [.test.com] was specified for this cookie
at org.apache.tomcat.util.http.Rfc6265CookieProcessor.validateDomain(Rfc6265CookieProcessor.java:181)
at org.apache.tomcat.util.http.Rfc6265CookieProcessor.generateHeader(Rfc6265CookieProcessor.java:123)
at org.apache.catalina.connector.Response.generateCookieString(Response.java:989)
at org.apache.catalina.connector.Response.addCookie(Response.java:937)

排查

根据异常栈找到了 Tomcat 中对应的文档,Tomcat 在新版中升级了 Cookie Processor, 使用了 org.apache.tomcat.util.http.Rfc6265CookieProcessor

而旧版本的Tomcat使用了 org.apache.tomcat.util.http.LegacyCookieProcessor 这个实现。

查阅了 Tomcat 中 Rfc6265CookieProcessor 相关的代码,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 private void validateDomain(String domain) {
int i = 0;
int prev = -1;
int cur = -1;
char[] chars = domain.toCharArray();
while (i < chars.length) {
prev = cur;
cur = chars[i];
if (!domainValid.get(cur)) {
throw new IllegalArgumentException(sm.getString(
"rfc6265CookieProcessor.invalidDomain", domain));
}
// labels must start with a letter or number
if ((prev == '.' || prev == -1) && (cur == '.' || cur == '-')) {
throw new IllegalArgumentException(sm.getString(
"rfc6265CookieProcessor.invalidDomain", domain));
}
// labels must end with a letter or number
if (prev == '-' && cur == '.') {
throw new IllegalArgumentException(sm.getString(
"rfc6265CookieProcessor.invalidDomain", domain));
}
i++;
}
// domain must end with a label
if (cur == '.' || cur == '-') {
throw new IllegalArgumentException(sm.getString(
"rfc6265CookieProcessor.invalidDomain", domain));
}
}

以上规则说明了域名必须是1-9、a-z、A-Z、. 、-这几个字符组成,且必须是数字或字母开头。

真相大白,这个.开头的泛域名被判定非法了。

解决方案

修改 Tomcat 实现

在 Tomcat配置文件中增加以下代码指定老版本 Cookie Processor 实现

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

添加后重启Tomcat生效

降级

降级 Tomcat 也可以解决这个问题