servlets - Undertow (JBoss 7) 在重定向时破坏 / 重新编码 URL 编码的参数
问题描述
也发布在 JBoss 论坛: https ://developer.jboss.org/thread/280195
更新 2019-06-26显然这现在被确认为 Undertow 中的一个错误,并在此处提交了一个拉取请求。
这是一个SSCCE。
我有一个非常简单的 Servlet,除了打印参数的值之外什么都不做:
public class TestServlet extends HttpServlet{
public void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
final String URL = req.getParameter("url");
System.out.printf("url parameter read as: [%s]\n", URL);
}
}
我的应用程序的 web.xml 配置为自动将http
访问重定向到https
:
<web-app>
...
<security-constraint>
<web-resource-collection>
<web-resource-name>SECURE</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
</web-app>
…而且我也有(在我的standalone-full.xml
配置文件中)redirect-socket
在定义中设置的属性http-listener
:
<http-listener name="default" socket-binding="http" redirect-socket="https" enable-http2="true"/>
如果我部署到 JBoss EAP 7.1 并在我的浏览器中输入以下 URL(其中参数带有“ http://www.google.comurl
”的 URL 编码值):
http://localhost:8082/get-parameter-test/min?url=http%3A%2F%2Fwww.google.com
…这是我在开发者控制台中看到的:
结果,自动重定向后,我的代码无法获得正确的url
参数值,我在日志文件中看到:
url parameter read as: [http%3A%2F%2Fwww.google.com]
但是,如果我部署到 JBoss EAP 6.2 并执行相同操作,则 URL 不会在重定向中被破坏,并且一切正常:
更新
这个答案表明JBoss 配置文件 ( ) 中的配置和undertow 系统中的decode-url
参数可能与此有关。这是错误的。我尝试了所有四种组合:http-listener
https-listener
standalong-full.xml
- http-listener:
decode-url
="false" 和 https-listener:decode-url
="false" - http-listener:
decode-url
="false" 和 https-listener:decode-url
="true" - http-listener:
decode-url
="true" 和 https-listener:decode-url
="false" - http-listener:
decode-url
="true" 和 https-listener:decode-url
="true"
在所有情况下,影响从 http 到 https 的重定向的 302 响应具有以下标头:
Location: https://localhost:8445/get-parameter-test?url=http%253A%252F%252Fwww.google.com
也就是说,在所有情况下,URL 都是错误的(如果你愿意,可以称它为重新编码,它是错误的 AFAIAC)。这种行为根本没有理由,也不是 EAP 6.2 所做的。参数的值decode-url
只影响HttpServletRequest#getRequest
servlet 中方法的行为,它对重定向的 URL 没有任何影响。
解决方案
更新 2019-06-26显然,现在已确认这是 Undertow 中的一个错误,并在此处提交了拉取请求
这就是最终对我有用的方法。首先,我从web.xml
整个<security-constraint>
元素中删除,因为我实施的解决方案不需要它。我还redirect-socket="https"
从<http-listener>
配置中删除了。这也是不需要的。所以这就是我的<http-listener>
样子<https-listener>
:
<http-listener name="default" socket-binding="http" enable-http2="true"/>
<https-listener name="https" socket-binding="https" security-realm="ApplicationRealm" enable-http2="true"/>
我认为以上内容正是您在 JBoss EAP 7.1 中开箱即用的内容,因此无需更改。
然后我创建了一个过滤器并将其添加到undertow子系统的<filters>
元素中:
<rewrite name="http-to-https" redirect="true" target="https://%h:8445%U%q"/>
%h
是远程主机名%U
是请求的 URL 路径%q
是查询字符串(?
如果存在则自动添加)
我在这里找到了上面的代码——我确信在其他地方有更规范的参考,但它们似乎有效。
最后,我在<server>/<host>
元素中(也在undertow子系统中)添加了对过滤器的引用以及谓词:
<server name="default-server">
<http-listener name="default" socket-binding="http" enable-http2="true"/>
<https-listener name="https" socket-binding="https" security-realm="ApplicationRealm" enable-http2="true"/>
<host name="default-host" alias="localhost">
<location name="/" handler="welcome-content"/>
<filter-ref name="server-header"/>
<filter-ref name="x-powered-by-header"/>
<filter-ref name="http-to-https" predicate="equals(%p, 8082)"/>
<http-invoker security-realm="ApplicationRealm"/>
</host>
</server>
使用上述配置,请求会被重定向,而无需重新编码 URL:
$ curl -I -L -k http://localhost:8082/get-parameter-test?url=http%3A%2F%2Fwww.google.com
HTTP/1.1 302 Found
Connection: keep-alive
Server: JBoss-EAP/7
Location: https://127.0.0.1:8445/get-parameter-test?url=http%3A%2F%2Fwww.google.com
Content-Length: 0
Date: Tue, 11 Jun 2019 17:43:23 GMT
HTTP/1.1 200 OK
Connection: keep-alive
X-Powered-By: Undertow/1
Server: JBoss-EAP/7
Content-Length: 0
Date: Tue, 11 Jun 2019 17:43:23 GMT
…并且从Java中正确读取了参数:
url parameter read as: [http://www.google.com]
无需decode-url="true"
在 http/https 侦听器中设置,因为这是默认值。
注意:以上导致 JBoss EAP 7.1 发送 302 重定向。我不知道如何配置 303 或 307 重定向。
最后的评论
上面的明显替代方法是使用HttpServletRequest#sendRedirect从应用程序代码以编程方式进行重定向。在这种情况下,您也不需要redirect-socket="https"
在您的http-listener
.
显然,该redirect-socket
属性只需要与<security-constraint>
应用程序的web.xml中的元素结合使用。那是因为否则(即,如果您的<security-constraint>
中有web.xml
但没有),redirect-socket
您http-listener
会受到以下打击:
ERROR [io.undertow.request] (default task-14) UT005001: An exception occurred processing the request: java.lang.IllegalStateException: UT010053: No confidential port is available to redirect the current request.
)。
但是,如果您同时拥有<security-constraint>
和redirect-socket
,则查询字符串在重定向的 URL 中被不必要地重新 URL 编码(并因此被破坏),如问题中所述。所以我不清楚<security-constraint>
JBoss EAP 7.1 中的用途是什么。
推荐阅读
- javascript - 无法加载插件 vue/Eslint 中断
- javascript - 在 raw-body 之后使用 express.json()
- azure-data-factory - 如何将整数存储到 Azure 数据工厂中的变量?
- c++ - libcurl 仅用换行替换回车 + 换行
- django-models - 如何从模型中获取 Django Shell 中的 is_active = False?
- python - 全局声明之前使用的 Python 3.7.3 SyntaxError 变量
- operating-system - Alpine linux 操作系统版本控制
- php - 带有自定义主题的 Wordpress 的 504 网关超时错误
- apache - 即使安装在正确的位置,Apache 也找不到目录
- javascript - 在Openedx Based Project中,Xblock自定义需要在javascript的textarea中添加CKEditor