tomcat对URL合法字符的判断(RFC 7230 and RFC 3986 异常排查)

文章探讨了Tomcat处理URL中特殊字符{}
  • 起因

有一个数据上报接口,之前在物理机上部署,数据上报正常。

最近将项目迁移到 docker 中,结果出现了异常如下:

Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level.
java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
    at org.apache.coyote.http11.InternalInputBuffer.parseRequestLine(InternalInputBuffer.java:192)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1028)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:637)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
  • 问题原因

问题排查过程:略

原因:请求中出现了字符"{"(示例请求)

https://127.0.0.1:8080/metric?data=[{%22app

在不更改接口数据的前提下,解决方案为:在tomcat的cataline.properties追加配置

tomcat.util.http.parser.HttpParser.requestTargetAllow=|{}

官方文档链接:http://tomcat.apache.org/tomcat-8.0-doc/config/systemprops.html#Other

tomcat.util.http.parser.HttpParser. requestTargetAllow

A string comprised of characters the server should allow even when they are not encoded. These characters would normally result in a 400 status.

The acceptable characters for this property are: |{ , and }

WARNING: Use of this option will expose the server to CVE-2016-6816.

If not specified, the default value of null will be used.

  • 问题来源

那么为什么之前接口不会出现异常呢?是tomcat版本不同导致的。

查看源码后发现:org.apache.tomcat.util.http.parser.HttpParser

tomcat 8.2.3 版本及 tomcat 7.0.82 ,都有如下代码,读取配置

String prop = System.getProperty("tomcat.util.http.parser.HttpParser.requestTargetAllow");
if (prop != null) {
    for (int i = 0; i < prop.length(); i++) {
        char c = prop.charAt(i);
        if (c == '{' || c == '}' || c == '|') {
            REQUEST_TARGET_ALLOW[c] = true;
        } else {
            log.warn(sm.getString("httpparser.invalidRequestTargetCharacter",
                    Character.valueOf(c)));
        }
    }
}

而tomcat 8.0.14 版本中并没有读取配置,对 | { } 的处理,而是默认为合法字符。

static {
    // Setup the flag arrays
    for (int i = 0; i < 128; i++) {
        if (i < 32) {
            isToken[i] = false;
        } else if (i == '(' || i == ')' || i == '<' || i == '>'  || i == '@'  ||
                   i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' ||
                   i == '/' || i == '[' || i == ']' || i == '?'  || i == '='  ||
                   i == '{' || i == '}' || i == ' ' || i == '\t') {
            isToken[i] = false;
        } else {
            isToken[i] = true;
        }
 
        if (i >= '0' && i <= '9' || i >= 'A' && i <= 'F' ||
                i >= 'a' && i <= 'f') {
            isHex[i] = true;
        } else {
            isHex[i] = false;
        }
    }
}

虽然没有进行全面的比对,但可以看出在 8.0.x 左右的一些版本中,tomcat.util.http.parser.HttpParser. requestTargetAllow 这个配置是没有生效的,即  | { } 这3个符号认为是合法的。

  • 结论:
  1. tomcat.util.http.parser.HttpParser. requestTargetAllow 这个字段可以解决URL中存在 | { } 字符的问题。
  2. tomcat自tomcat 8.0.35版本之后对URL参数做了比较规范的限制,必须遵循RFC 7230 and RFC 3986规范,对于非保留字字符(json格式的请求参数)必须做转义操作。

 

 

 

 

 

转载于:https://my.oschina.net/pding/blog/1794176

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值