Undertow(JBoss 7)在重定向上修改/重新编码URL编码的参数

时间:2019-06-07 19:43:14

标签: servlets jboss jboss7.x undertow jboss-eap-7

也发布在JBoss论坛中: https://developer.jboss.org/thread/280195

更新2019-06-26 显然,现在已确认这是Undertow中的错误,并提交了here的拉取请求。

这是一个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(其中url参数带有URL编码值“ http://www.google.com”)

http://localhost:8082/get-parameter-test/min?url=http%3A%2F%2Fwww.google.com

…这是我在开发人员控制台中看到的:

enter image description here

结果,在自动重定向之后,我的代码无法获得url参数的正确值,并且在日志文件中看到了

url parameter read as: [http%3A%2F%2Fwww.google.com]

但是,如果我部署到JBoss EAP 6.2并执行相同的操作,则URL在重定向中不会被破坏,并且一切正常:

enter image description here

更新

this answer建议在JBoss配置文件(decode-url)中的undertow系统中http-listenerhttps-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参数的值仅影响Servlet内部HttpServletRequest#getRequest方法的行为,在重定向的URL中没有任何作用。

2 个答案:

答案 0 :(得分:1)

这是最终为我工作的东西。 首先,我从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是查询字符串(如果存在,则自动附加?

我发现了上面的代码here-我敢肯定,在其他地方还有更多的规范性引用,但它们似乎有用。

最后,我在<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]

无需在http / https侦听器中设置decode-url="true",因为这是默认值。

注意:上面的操作导致JBoss EAP 7.1发送302重定向。我不知道如何配置303或307重定向。

最后的话

上述明显的替代方法是使用HttpServletRequest#sendRedirect从应用程序的代码中以编程方式进行重定向。同样在这种情况下,您不需要在您的redirect-socket="https"中需要http-listener

显然,redirect-socket属性仅与应用程序的 web.xml 中的<security-constraint>元素结合在一起才是必需的。那是因为否则(例如,如果您的<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编码(并因此被篡改)。因此,我不清楚JBoss EAP 7.1中<security-constraint>的用途是什么。

答案 1 :(得分:0)

您的网址没有被重新编码。问题是从http重定向到https时重新编码或URL。您正在将编码的url参数传递到http,即http%3A%2F%2Fwww.google.com。

http://www.google.com --encode--> http%3A%2F%2Fwww.google.com --re-encode--> http%253A%252F%252Fwww.google.com

在您重新编码url时,'%'被编码为'%25'。

要禁用此行为,您需要在列表器中进行更改。有一个名为 decode-url 的属性,可用于禁用/启用此行为。

  

decode-url:URL应该被解码。如果未设置为   如果为true,则网址中的百分比编码字符将保持不变。

有关Undertow子系统的更多信息,请参考以下链接。 https://docs.jboss.org/author/display/WFLY/Undertow+subsystem+configuration

注意:此功能可能已在JBoss 6.2上使用,因为在JBoss 6.2子系统中,此配置称为WEB,在JBoss EAP 7+中由Undertow代替