The valid characters are defined in RFC 7230 and RFC 3986错误解决方式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了The valid characters are defined in RFC 7230 and RFC 3986错误解决方式相关的知识,希望对你有一定的参考价值。

参考技术A 还有一些字符,当他们直接放在Url中的时候,可能会引起解析程序的歧义。这些字符被视为不安全字符,原因有很多。

将请求值URL编码(但是spring boot默认只会URL解码一次,二次解码需要另行添加)

更换Tomcat为较低版本(提示:同样的问题也存在于 >=8.0.39和>=9.0.0.M12)

使用POST提交数据内容(body中)

1.~/conf/catalina.properties中,找到最后注释掉的一行 #tomcat.util.http.parser.HttpParser.requestTargetAllow选项,改成tomcat.util.http.parser.HttpParser.requestTargetAllow=|,选项是按照字符分隔为一个数组,表示放行["|","",""]
2.或者你可以在~/conf/catalina.properties最后一行添加org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true

在启动时加入tomcat.util.http.parser.HttpParser.requestTargetAllow=|
实例:# java -jar -Dtomcat.util.http.parser.HttpParser.requestTargetAllow=| demo-0.0.1-SNAPSHOT.jar

异常:Invalid character found in the request target. The valid characters are defined in RFC 3986

一、背景

  事情是这样的,前几天做一个基本的数据库“增删改查”的需求,前端传参的方式是“JSON字符串”,后端接收到此参数后,使用阿里巴巴fastjson进行解析,然后入库。需求很简单吧,但是偏偏遇到问题了。

  我发现,JSON字符串里面无数组,纯粹的都是json结构的时候,即都是“{}”时,不会报错,传参入库没问题。但是只要传参的值里面有数组,即有“[]”的结构时,就报错。报错内容如下(我的tomcat版本是8.5.45):

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.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:479)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:684)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:800)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1471)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    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:748)

 

二、原因

  tomcat的原因。 tomcat严格按照RFC规范进行范文解析,随着网络环境的变化,RFC规范也在不断的修改和升级中,发布了好多版本。而tomcat的不同版本中,采用的RFC规范的版本是不同的。所以你会在下文发现,有的低版本tomcat没有这个问题。

  tomcat自tomcat 8.0.35版本之后对URL参数做了比较规范的限制,必须遵循RFC 7230 and RFC 3986规范,对于非保留字字符(json格式的请求参数)必须做转义操作。例如:RFC 3986规范定义了Url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4个特殊字符以及所有保留字符(RFC3986中指定了以下字符为保留字符:! * ’ ( ) ; : @ & = + $ , / ? # [ ])。

  Request For Comments(RFC),是一系列以编号排定的文件。文件收集了有关互联网相关信息,以及UNIX和互联网社区的软件文件。目前RFC文件是由Internet Society(ISOC)赞助发行。基本的互联网通信协议都有在RFC文件内详细说明。RFC文件还额外加入许多在标准内的论题,例如对于互联网新开发的协议及发展中所有的记录。因此几乎所有的互联网标准都有收录在RFC文件之中——百度百科。

  附上网络大牛的源码分析:

分析的是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 {
    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 == ‘	‘) {
            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个符号认为是合法的。

 

三、解决

  注:我是使用“方法五”解决问题的,推荐“方法五”。

  方法一:换到低版本的Tomcat。

  方法二:在Catalina.properties中添加tomcat.util.http.parser.HttpParser.requestTargetAllow=|{}这个东西明显是允许“|”和大括号的,但是我现在的问题是中括号。

  方法三:添加tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true这个是允许url中带有特殊字符的。试过了,也不好使。

  方法四:对传递的“JSON字符串”进行url编码后在传递,可以规避这个方括号。前端用“encodeURI(xxx)”方法编码,后端用“URLDecoder.decode(xxx, "utf-8")”解码即可。

  方法五:在tomcat目录的conf文件夹下,server.xml的Connector中添加了这个relaxedQueryChars="[,]"。

      注:

1、如果还有其他特殊的字符串,也可以直接添加到这个属性里;

2、如果你是springboot项目,可以在SpringBootApplication的的main方法中增加:System.setProperty("tomcat.util.http.parser.HttpParser.requestTargetAllow","[]");       技术图片

参考

1、https://blog.csdn.net/Hitler698/article/details/85720156

2、https://my.oschina.net/pding/blog/1794176

3、http://www.bubuko.com/infodetail-3238579.html

以上是关于The valid characters are defined in RFC 7230 and RFC 3986错误解决方式的主要内容,如果未能解决你的问题,请参考以下文章

Springboot 报错 Invalid character found in the request target. The valid characters are defined in RFC

异常:Invalid character found in the request target. The valid characters are defined in RFC 3986

问题Invalid character found in the request target. The valid characters are defined in RFC 7230 and (代

Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC(

解决Invalid character found in the request target. The valid characters are defined in RFC 7230 and RF

解决Invalid character found in the request target. The valid characters are defined in RFC 7230 and RF