Undertow (JBoss 7) искажает / перекодирует URL-кодированный параметр при перенаправлении - PullRequest
0 голосов
/ 07 июня 2019

Опубликовано также на форумах JBoss: https://developer.jboss.org/thread/280195

обновление 2019-06-26 по-видимому, теперь это подтверждается как ошибка в Undertow с отправкой запроса на получение здесь .

Это SSCCE.

У меня есть очень простой сервлет, который ничего не делает, кроме печати значения параметра:

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-адреса "*"1028 *

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

update

этот ответ предполагает, что параметр decode-url в конфигурации http-listener и https-listener в системе отката в файле конфигурации JBoss (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"

Во всех случаях ответ 302, который осуществляет перенаправление с http на https, имеетследующий заголовок:

Location: https://localhost:8445/get-parameter-test?url=http%253A%252F%252Fwww.google.com

То есть во всех случаях URL-адрес искажен (назовите его перекодированным, если хотите, он искажен AFAIAC).Нет никаких причин для такого поведения, и это не то, что делает EAP 6.2.Значение параметра decode-url влияет только на поведение метода HttpServletRequest#getRequest в вашем сервлете, оно никак не влияет на перенаправленный URL.

Ответы [ 2 ]

1 голос
/ 11 июня 2019

Вот что в итоге сработало для меня. Прежде всего, я удалил из своего 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 из коробки, поэтому нет необходимости менять это.

Затем я создал фильтр и добавил его в элемент <filters> подсистемы undertow :

<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
* * 1 042 & hellip; и параметр правильно читается из Java:
url parameter read as: [http://www.google.com]

Нет необходимости устанавливать decode-url="true" в прослушивателях http / https, поскольку это значение по умолчанию.

NB. Вышеприведенное заставляет 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.

0 голосов
/ 10 июня 2019

Ваш URL не искажается, он перекодируется. Проблема заключается в перекодировке или URL при перенаправлении с http на https. Вы передаете закодированный параметр 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, тогда символы в процентах в URL останутся без изменений.

См. Следующую ссылку для получения дополнительной информации о подсистеме Undertow. https://docs.jboss.org/author/display/WFLY/Undertow+subsystem+configuration

Примечание : эта функциональность могла работать на JBoss 6.2, потому что в JBoss 6.2 подсистема для этой конфигурации называется WEB, которая заменяется на Undertow в JBoss EAP 7 +

...