Last active
July 5, 2022 17:41
-
-
Save Argelbargel/eea6dc1b3d986d80c3843d3375c78365 to your computer and use it in GitHub Desktop.
How to use Apache 2.4+ as proxy for Rest-Service which allows encoded slashes (%2F)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
###################################################################################################################################### | |
# When to use: | |
# You have a REST-Service which accepts requests like /endpoint/id%2Fwith%2Fslashes and you want to proxy it through Apache, | |
# either to load-balance multiple server or to add authentication to a service you can not modify for that. | |
# | |
# Resolves these problems: | |
# - Apache2 prevents requests to URIs containing encoded slashes by default and rejects them by returning 404 Not Found | |
# - Additionally mod_proxy canonicalizes URLs replacing %2F with %252F before passing the request to the backend | |
# - while Apache 2.4 added the special keyword "nocanon" to the ProxyPass directive there is a security feature built-in that | |
# enforces canoncialisation when the incoming request URL matching the given prefix (e.g. "/") contains an unescaped path | |
# (indicated by [proxy:warn] AH01136: Unescaped URL path matched ProxyPass; ignoring unsafe nocanon in the error log) | |
# - ProxyMatch does not have the keyword "nocanon" so when matching by pattern canonicalisation is always enforced | |
# | |
# How it works: | |
# Instead of using ProxyPass or ProxyMatch this config-file uses rewrite-rules to pass matching requests to mod_proxy without it | |
# interfering with the URL passed to the backend. To prevent any modification by apache the path is captured from the raw request | |
# line using a rewrite-condition | |
# | |
# Caveats: | |
# - this disables reasonable and generally useful security-features. Ensure that the backend validates the passed request-uris! | |
# - this example only contains the minimal directives, omiting boiler-plate like log-configuration, authentication etc. | |
# | |
# Useful links: | |
# - https://httpd.apache.org/docs/2.4/mod/core.html#allowencodedslashes | |
# - https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#proxypass | |
# - https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html | |
# - https://httpd.apache.org/docs/2.4/rewrite/flags.html#flag_p | |
# - https://stackoverflow.com/ and https://serverfault.com/ | |
# (while they did not provide me the answer in this case, they did thousands of times before ;-) | |
################################################################################################################################## | |
# Required modules (remove if statically compiled into your apache-installation) | |
LoadModule proxy_module modules/mod_proxy.so | |
LoadModule proxy_http_module modules/mod_proxy_http.so | |
LoadModule rewrite_module modules/mod_rewrite.so | |
# ensures that encoded slashes are accepted and passed as is | |
AllowEncodedSlashes NoDecode | |
# rewrite-rules selecting requests to pass to the backend | |
RewriteEngine on | |
# rules for requests that should not be proxied must come first (apache's server-status in my case) | |
# RewriteCond %{SCRIPT_FILENAME} ^/server-status | |
# RewriteRule ".*" - [PT,L] | |
# followed by rule(s) sending requests to the backend. This example passes everything not excluded above to the backend. | |
RewriteCond %{THE_REQUEST} ^[^/]+/+([^?&#\s]*) | |
RewriteRule "(.*)" "http://<your-backend>/%1" [NE,P] | |
ProxyPassReverse "/" "http://<your-backend>/" | |
# if your case is really simple you could use a single rule like this one instead of the above | |
# RewriteCond %{THE_REQUEST} ^[^/]+/+(?!server-status)([^?&#\s]*) | |
# RewriteRule "(.*)" "http://<your-backend>/%1" [NE,P] | |
# ProxyPassReverse-Rules matching the above rewrite-rules | |
ProxyPassReverse "/" "http://<your-backend>/" | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment