Apache ProxyPass not forwarding original http headers to workers - proxypass

I am sending a request to httpd with a setHeader, named.
I see that header if I do not use ModProxy, using getRequestHeader with the header name.
However I need the header information in the ProxyPass workers.
How can I get Apache to forward the headers in ProxyPass.
I have searched for an answer for this for quite a while but I cannot find something that works.
My ProxyPass directive:
<IfModule mod_proxy_fcgi.c>
#No PATH_INFO with mod_proxy_fcgi unless this is set
SetEnvIf Request_URI . proxy-fcgi-pathinfo=1
ProxyPass "/gas30/" "fcgi://192.168.1.5:6394/"
Alias "/gas30" "/opt/fourjs30/gst/gas/bin/fastcgidispatch enablereuse=on"
ProxyPass "/gas31/" "fcgi://192.168.1.5:6395/"
Alias "/gas31" "/opt/fourjs31/gst/gas/bin/fastcgidispatch enablereuse=on"
</IfModule>
I am using Apache/2.4.6 (CentOS 7)
Thanks in advance
Johan
I use tcpdump to display the header received on Listen port 6380
Just to make sure it is there.
http_auth: Y2FuY3VuQG1ic2JiYW5rLmNvbScgJzExMTExMTExJyAnJDJhJDEyJDJwMlFOMVNZVURldUlpcWw2R3ZWMk83Mi45QUtXSlROcUlnWDRFQVUvZnJjU01SZnJNQXVL
That is the correct header.
I have tried a lot of things to forward that to port 6395.
I am totally stuck on that though.
The last thing I tried was to hard code it under Location.
But I do not see it in tcpdump
<Location /gas31>
Header add http_auth "Y2FuY3VuQG1ic2JiYW5rLmNvbScgJzExMTExMTExJyAnJDJhJDEyJDJwMlFOMVNZVURldUlpcWw2R3ZWMk83Mi45QUtXSlROcUlnWDRFQVUvZnJjU01SZnJNQXVL"
RequestHeader set http_auth "Y2FuY3VuQG1ic2JiYW5rLmNvbScgJzExMTExMTExJyAnJDJhJDEyJDJwMlFOMVNZVURldUlpcWw2R3ZWMk83Mi45QUtXSlROcUlnWDRFQVUvZnJjU01SZnJNQXVL"
Order Deny,Allow
Deny from all
Allow from all
</Location>
I have come to the end of the line with this one, I tried everything and I cannot get the request header to pass through.
.
I can either put my header in the JSON messages I send or move to nginx.
Since I have been using httpd for years I will take the first option.
I saw this post but I cannot add a comment due to reputation.
Is this relevant ?
If it is where do I put these instructions ?
It seems this line preserves the Header for reasons I don't quite understand:
SetEnvIf HTTP_MY_HEADER "(.*)" MY_HEADER=$0
The reason I don't understand this is that I am setting an Env var here, not a header -- are Env vars automatically turned into headers?
I though I might have to do this also, but was unnecessary:
RequestHeader set HTTP_MY_HEADER "${MY_HEADER}e"
I suppose this is an answer as "it works", although I would love to know why...

Related

How to use ProxyPass to send a query parameter without encoding it?

In my apache configuration I am matching on some url and trying to redirect that to another location. For the most part this configuration is working. The part that is not is the query parameter on the proxy pass url. All my research is leading me to a RewriteRule, but that makes no sense to me since I am completely throwing away the incoming url as it doesn't matter after it's used to match the Location block.
<Location "/src">
ProxyErrorOverride Off
ProxyPass https://example.com/dst/v1234?user=me
ProxyPassReverse https://example.com/dst/v1234?user=me
Header set Cache-Control "max-age=604800, public"
</Location
When I am testing I can see the following:
Web Server: POST http://localhost/src -d { "data": true }
App Server: POST https://example.com/dst/v1234%3fuser=me -d { "data": true }
The App Server doesn't know how to interpret the %3f even though that's url encoding for the question mark (?). The App Server is not under my control and I can't change that code to decode this for me. How can I get Apache to send the question mark (?) instead of the url encoded variant?
After much research and another very helpful Stack Overflow post. I found a solution!
ProxyPass /webservice balancer://api/webservice nocanon
Apache mod_proxy url encoding
The answer is to use nocanon.
<Location "/src">
ProxyErrorOverride Off
ProxyPass https://example.com/dst/v1234?user=me nocanon
ProxyPassReverse https://example.com/dst/v1234?user=me
Header set Cache-Control "max-age=604800, public"
</Location
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.
https://httpd.apache.org/docs/2.4/mod/mod_proxy.html

Apache `SetEnvIf` and duplicated headers

We are using this kind of configuration to grant access to one of our sites
<LocationMatch "/*">
Order deny,allow
Deny from all
Allow from 127.0.0.0/8
SetEnvIf X-Forwarded-For "(,| |^)192\.168\." WhiteIP
SetEnvIf X-Forwarded-For "(,| |^)172\.(1[6-9]|2\d|3[0-1])\." WhiteIP
SetEnvIf X-Forwarded-For "(,| |^)10\." WhiteIP
Allow from env=WhiteIP
</LocationMatch>
Indeed, there is another reverse proxy in front of this Apache server so all clients will have the header.
Problem is sometimes client have others proxies on their side and the X-Forwarded-For Header wil be either duplicated or concatenated. We handle the concatenation correctly with the (,| |^) regexp trick, but the problem is that Apache seems to run the SetEnvIf only against the first occurrence of the Header.
Documentation is unclear about this behavior. Any idea on how to handle this kind of case ? (note: we cannot control how our reverse proxy works, only Apache) Could that be qualified as a bug ? I couldn't find the right way to ask google about this and found no result. I've also tried digging into the mod_setenvif's code but that's out of my league.
Precision : CentOS 6, Apache 2.2.15 latest patch version
If SetEnvIf sees regex-like characters in the first argument, it will go into a mode where it iterates over all headers that match the regex until there's a match.
You could use this by specifying ^X-Forwarded-For$ which would iterate over the multiple occurrences of this 1 header.
This is a workaround for the longstanding behavior of how many modules treat multiple occurrences. This should be documented better as a module-specific solution.

Get mod_proxy to pass a custom header to backend

I have a Python backend that is being reverse proxied by Apache/mod_proxy using fcgi (httpd 2.4 on rhel7).
I have a client that sets a custom header in the request, however mod_proxy does not appear to be sending that header on to the backend.
I know something similar exists for the host as ProxyPreserveHost - I would like to know how to do something similar for a custom header.
Can I do that with mod_proxy, or will I need to fall back on to mod_rewrite in some way?
TIA
It seems this line preserves the Header for reasons I don't quite understand:
SetEnvIf HTTP_MY_HEADER "(.*)" MY_HEADER=$0
The reason I don't understand this is that I am setting an Env var here, not a header -- are Env vars automatically turned into headers?
I though I might have to do this also, but was unnecessary:
RequestHeader set HTTP_MY_HEADER "${MY_HEADER}e"
I suppose this is an answer as "it works", although I would love to know why...

How to set up a seamless proxy in Apache to get around my ISP's firewall?

I'm really hoping someone can help me out with this because I've been at it for several days and I think I'm going crazy!
I'm trying to do what to me sounds like a stupidly simple thing. I want to set up a proxy server using Apache on a dedicated machine that I rent so that I can get around my ISPs nonsense firewall. I am aware that I could use a VPN, I don't want to do that for reasons that should hopefully become clear after I explain the details of what I want.
First of all, I don't want the proxy server to be used for every request. Only for the sites that are blocked by my ISP.
Suppose I try to access blockedsite.com/path/to/resource and it fails. I then simply want to change the URL in the address bar to proxy.myserver.com/proxy/blockedsite.com/path/to/resource and have Apache handle everything to provide me with a seamless experience. That means,
ProxyPassReverse should modify the response headers to use to the proxy server.
All URLs in the response body should be modified to use the proxy
Here's what I have so far:
<VirtualHost *:80>
ServerName proxy.myserver.com
ProxyRequests off
ProxyPass /proxy/ http://
ProxyPassReverse /proxy/ http://
ProxyPassReverse /proxy/ https://
ProxyHTMLURLMap http:// /proxy/
ProxyHTMLURLMap https:// /proxy/
<Location /proxy/>
ProxyPassReverse /
AddOutputFilterByType SUBSTITUTE text/html
Substitute "s|</title>|</title><meta name='referrer' content='no-referrer' />|ni"
ProxyHTMLEnable On
#ProxyHTMLURLMap / /app1/
RequestHeader unset Accept-Encoding
Order allow,deny
Allow from all
</Location>
</VirtualHost>
This setup works beautifully for URLs that don't try to redirect me elsewhere. But if for example I try to access proxy.myserver.com/proxy/facebook.com I am still being redirected on the client side to https://www.facebook.com instead of https://proxy.myserver.com/proxy/www.facebook.com as I would like. The extra weird thing is that when I set up my own test site which does nothing except redirect me to an HTTPS address, the ProxyPassReverse rule for HTTPS does actually seem to work... but not when I try to access sites like Facebook or Google.
I see no reason to ramble on about my issues, what I'm looking for is astoundingly simple: a transparent, seamless experience! Aside from sticking proxy.myserver.com/proxy/ in front of the URL in the address bar, I shouldn't have to do anything else for it to work. Yet that is not the case and despite over a week of searching, I have found nothing online to help me with this. It's as if I'm the only person in the universe to want to create a simple proxy with Apache that actually works as a firewall-get-arounder.
Please can someone lend me a hand here?! Even just to tell me I'm going about this all wrong and should give up and install Squid or something??
Your last paragraph contains the right answer. You should indeed just "install Squid or something". In particular, I'd recommend Apache Traffic Server - http://trafficserver.apache.org/ - this is exactly what it's made for.
While Apache httpd can do proxying, it's not it's primary function, and so there are always things that will end up being frustrating with it. We could get your above scenario working, but it's really not the right tool for the job.

conditional proxypass ajp rules using ip whitelist

I've successfully created a ProxyPass ajp rule which works fine, but now i want to restrict the access of certain urls using an ip-whitelist. In other words, when someone comes from an ip that is not on the whitelist the request should not be proxypassed (and, ideally, some sort of access denied should be issued)
i don't have control over the machine i'm proxy-passing to, so i can't put the ip-whitelist on that machine's configuration. That's why i'm trying to configure this on the same machine that has the proxypass rule.
Defining a <Location /path> with 'Allow from'-rules doesn't work, because the request is still proxypassed. I guess this simply means the proxypass rules preceed the location-rules.
I've tried to work around it by setting an environment variable depending on the remote-address (because then i could proxy non-whitelist-ips to nonexistent url - not pretty, but it would achieve the goal), but it seems the proxypass rule doesn't work with environment variables. Something as simple as this:
SetEnv custom_proxypath=/
ProxyPass %{ENV:custom_proxypath} ajp://10.50.40.21:8009/
ProxyPassReverse %{ENV:custom_proxypath} ajp://10.50.40.21:8009/
doesn't work. while
ProxyPass / ajp://10.50.40.21:8009/
ProxyPassReverse / ajp://10.50.40.21:8009/
works perfectly.
I'm out of options. Does anyone else have a suggestion how to approach this?
I learned this today.... SetEnv is applied later in the request cycle than the ProxyPass, so it isn't set in time. However, SetEnvIf is applied early enough, as are environment variables set with RewriteCond/RewriteRule. You should be able to refactor this to a SetEnvIf that is always true and that will do the trick.