Encode URL wihthin URL – apache mod-proxy (ProxyPass)

apache-2.2PROXYproxypassvirtualhost

I have a ProxyPass configured to reach the following: On my server I start a service which provides a Rest-API listening on port 7777. From the client side, I want to be able to call this API like this: http://example.org/servicename/PARAMETER

A full call to this API should look like this: HTTP PUT @ http://example.org/servicename/PARAMETER (where PARAMETER is some string). Internally this should translate to the following url: http://server.ip:7777/servicename/PARAMETER

Everything works as expected as long as the PARAMETER is not (!) like this: http://parameter.org (actually I need to URL encode it: http%3A%2F%2Fparameter.org). So all in all, the call is http://example.org/servicename/http%3A%2F%2Fparameter.org

The http:// in the parameter confuses apache leading to the following error message in the reply to the call:

!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /servicename/http://parameter.org was not found on this server.</p>
<hr>
<address>Apache/2.2.22 (Debian) Server at example.org Port 80</address>
</body></html>

If I replace http%3A%2F%2Fparameter.org with, for instance, test, everything works as it should. Somehow the http:// in the parameter confuses apache. Is there a way to let apache ignore it?

My current configuration of this vhost looks like this:

<VirtualHost *:80>
        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/example
        ServerName example.org
        ErrorLog /var/log/apache2/example_error.log
        LogLevel warn
        CustomLog /var/log/apache2/example_access.log combined

    <IfModule mod_proxy.c>
        ProxyRequests Off

        ProxyPass / http://localhost:7777/
        ProxyPassReverse / http://localhost:7777/
    </IfModule>
</VirtualHost>

Prerequisites:

  • I am not able to change the behavior of the API. it's third party.
  • I need to be able to provide URLs as parameters.

Edit 1:

tail -f /var/log/apache2/example_access.log yields

128.xxx.xxx.xxx - - [19/Aug/2015:16:53:17 +0200] "PUT /servicename/http%3A%2F%2Fparameter.org HTTP/1.1" 404 521 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36"

Best Answer

In the default Apache configuration, the AllowEncodedSlashes directive is set to off. This means that: "...The AllowEncodedSlashes directive allows URLs which contain encoded path separators [...] to be used in the path info. With the default value, Off, such URLs are refused with a 404 (Not found) error. ..."

So the problem is that mod_proxy is not proxying your URL-based POST requests, as Apache is refusing them (with a 404) before mod_proxy taking action.

Another possible problem relates to the URL-encoding process: your apache (front-end) will surely receive a properly URL-encoded string (the one you're sending to it: http://example.org/servicename/http%3A%2F%2Fparameter.org ) and I expect it (apache) will URL-decode it while internally processing related POST request. So I expect that mod_proxy, inside Apache, will receive a real URL (not encoded) and I wonder if, while proxying, it will perform an URL-encoded cycle. On the official ProxyPass documentation I see: "Normally, mod_proxy will canonicalise ProxyPassed URLs. But this may be incompatible with some backends, particularly those that make use of PATH_INFO. The optional nocanon keyword suppresses this and passes the URL path "raw" to the backend. Note that this keyword may affect the security of your backend, as it removes the normal limited protection against URL-based attacks provided by the proxy", so you should evaluate also the usage of the "nocanon" option.

Both issues (AllowEncodedSlashes and nocanon) have been mentioned in this StackOverflow question