Tomcat 8 无法处理带有“|”的获取请求在查询参数中?

Tomcat 8 is not able to handle get request with '|' in query parameters?

我正在使用 Tomcat 8. 在一种情况下,我需要处理来自外部源的外部请求,其中请求有一个由 |.

分隔的参数

请求看起来像这样:

http://localhost:8080/app/handleResponse?msg=name|id|

在这种情况下,我收到以下错误。

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:467)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:667)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:789)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
    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:745)

编辑 1

它适用于 Apache Tomcat 8.0.30 但不适用于 Tomcat 8.5

逃避它。管道符号是一种随着时间的推移和浏览器之间的不同处理方式。例如,Chrome 和 Firefox 在 copy/paste 时以不同的方式转换 URL with pipe。然而,与 Tomcat 8.5 最兼容和必要的似乎是逃避它:

http://localhost:8080/app/handleResponse?msg=name%7Cid%7C

所有主要 Tomcat 版本中都引入了此行为:

  • Tomcat 7.0.73, 8.0.39, 8.5.7

要修复,请执行以下操作之一:

  • 设置relaxedQueryChars允许这个字符 (推荐,
  • 设置requestTargetAllow选项 (在 Tomcat 8.5 中已弃用)().
  • 您可以降级到旧版本之一(不推荐 - 安全)

基于 changelog,这些更改可能会影响此行为:

Tomcat 8.5.3:

Ensure that requests with HTTP method names that are not tokens (as required by RFC 7231) are rejected with a 400 response

Tomcat 8.5.7:

Add additional checks for valid characters to the HTTP request line parsing so invalid request lines are rejected sooner.


最好的选择(遵循标准) - 你想在客户端编码你的URL:

encodeURI("http://localhost:8080/app/handleResponse?msg=name|id|")
> http://localhost:8080/app/handleResponse?msg=name%7Cid%7C

或者只查询字符串:

encodeURIComponent("msg=name|id|")
> msg%3Dname%7Cid%7C

它将保护您远离其他有问题的角色 (list of invalid URI characters)。

因为 Tomcat 7.0.76, 8.0.42, 8.5.12 您可以定义 属性 requestTargetAllow 以允许使用禁止字符。

将此行添加到您的 catalina.properties

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

URI 编码为 UTF-8,但 Tomcat 将其解码为 ISO-8859-1。您需要编辑 server.xml 中的连接器设置并添加 URIEncoding="UTF-8" 属性。

或在 application.properties

上编辑此参数

server.tomcat.uri-编码=utf-8

参数 tomcat.util.http.parser.HttpParser.requestTargetAllow 自 Tomcat 8.5 起已弃用:tomcat official doc

您可以在连接器定义中使用 relaxedQueryChars / relaxedPathChars 以允许这些字符:tomcat official doc.

问题: Tomcat (7.0.88) 抛出以下导致 400 – 错误请求的异常。

java.lang.IllegalArgumentException: Invalid character found in the request target. 
The valid characters are defined in RFC 7230 and RFC 3986.

从 7.0.88 开始的大多数 tomcat 版本都会出现此问题。

解决方案:(由 Apache 团队建议):

Tomcat 提高了安全性,不再允许在查询字符串中使用原始方括号。在请求中我们有 [](方括号)所以请求没有被服务器处理。

在server.xml标签下添加relaxedQueryChars属性(%TOMCAT_HOME%/conf):

<Connector port="80" 
           protocol="HTTP/1.1"
           maxThreads="150"
           connectionTimeout="20000"
           redirectPort="443"
           compression="on"
           compressionMinSize="2048"
           noCompressionUserAgents="gozilla, traviata"
           compressableMimeType="text/html,text/xml"
                                     relaxedQueryChars="[,]"
             />

如果应用程序需要更多 tomcat 默认不支持的特殊字符,则在 relaxedQueryChars 属性中添加这些特殊字符,如上逗号分隔。

将“relaxedQueryChars”属性添加到 server.xml 对我有用:

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="443" URIEncoding="UTF-8" relaxedQueryChars="[]|{}^&#x5c;&#x60;&quot;&lt;&gt;"/>