Detect apache reverse proxy programmatically - apache

I want to proxy a website – let’s call it “APP” - through Apache 2.4 using two different reverse proxies with different host names (virtual hosts). Let’s call those proxies “Alfa” and “Beta”. I want Alfa to be the “public proxy” which will show the normal version of the website. The Beta proxy will limit public access to certain client IPs, but here I want to show – on top of each page of the website – some type of sensitive information. Let’s call those portions of sensitive information “SENS”.
Here’s my current apache config.
Listen 443
NameVirtualHost *:443
SSLStrictSNIVHostCheck off
## Virtual host for the Alfa Proxy
<VirtualHost *:443>
ServerName alfa.mysite.org
RewriteEngine On
<Location /app/>
ProxyPass http://x.x.x.x:8080/app/
ProxyPassReverse http://x.x.x.x:8080/app/
</Location>
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile conf/alfa.crt
SSLCertificateKeyFile conf/alfa.key
</VirtualHost>
## Virtual host for the Beta Proxy
<VirtualHost *:443>
ServerName beta.mysite.org
RewriteEngine On
<Location /app/>
Require ip 192.168.0
ProxyPass http://x.x.x.x:8080/app/
ProxyPassReverse http://x.x.x.x:8080/app/
</Location>
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile conf/beta.crt
SSLCertificateKeyFile conf/beta.key
</VirtualHost>
In order to show SENS only to the users of Beta, I need to programmatically detect which proxy requests come from. Now, I’ve looked into the use of Reverse Proxy Request Headers such as “X-Forwarded-Server”. Let’s say I define some kind of security filter in APP (e.g Spring Filter) that allows SENS to be rendered on page only if X-Forwarded-Server equals “beta.mysite.org”. This should work just fine.
But my question is this: Can I be sure not some kind of tampering with the proxy headers occur that would allow users of the alfa.mysite.org actually view the SENS-portions of my website?
If so, are there any other ways of doing this a “secure manner”.
Having two different versions of APP or deploying APP on two different containers is something I want to avoid here.
Any comments or suggestions are appreciated.

According to the Apache documentation, the x-forwarded-server header can be a comma separated list when multiple proxies are used. So I wouldn't consider it safe from a security point of view.
Under the assumption that your backend server is not directly access, you could try the following.
Set your own HTTP Header which value changes depending on which VirtualHost it passes.
You only have to check then for the existence of the header in the backend.
ServerName alfa.mysite.org
RewriteEngine On
<Location /app/>
#Set - The request header is set, replacing any previous header with this name
RequestHeader set MyCustomHeader "remote"
</Location>
ServerName beta.mysite.org
RewriteEngine On
<Location /app/>
Require ip 192.168.0
#The request header is set, replacing any previous header with this name
RequestHeader set MyCustomHeader "local"
..
</Location>

Related

Reverse Proxy setup with apache

I am using this config with apache 2.4.53 and declaring a reverse proxy for 2 different domains, each with an identical config as shown.
<VirtualHost *:443>
ServerName www.example.com
SSLProxyEngine on
ProxyPreserveHost On
<Location "/">
Require all granted
ProxyPass http://192.168.163.10/
ProxyPassReverse http://192.168.163.10/
</Location>
SSLEngine on
SSLCertificateFile /etc/httpd/conf/vhosts/certs/cert.pem
SSLCertificateKeyFile /etc/httpd/conf/vhosts/certs/privkey.pem
SSLCertificateChainFile /etc/httpd/conf/vhosts/certs/fullchain.pem
</VirtualHost>
The request is going down to a target server using apache 2.2.22.
There www.example.com is declared as <VirtualHost *:80>.
The content of the website delivered is shown and https is used. Nevertheless I am facing problems using the CMS-interfaces (two different CMSes) the target is providing. Both let me log in successfully but one (silverstripe) is not showing the admin interface at all, the other (modx) is showing it but if I like to save my content it will display ...saving... all the time but won't save at all. Both is working with reverse proxy when the <VirtualHost *:80> at the RP is listening http.
Maybe my general understanding about RP is wrong. Is it okay to define it like I did and hope to get a valid https connection? It is obvious that the last step (RP-> target) is not encrypted, so maybe this is a no-go?
If it is a valid config has anyone got an idea why (maybe cookies?) this behaviour appears?
Any help is very welcome.
Thanks.

Blazor / Kestrel / Apache: How to configure properly?

I know, I know, Apache is not the best tool to use as HTTP proxy, however I need it on my server.
Here's my virtual host configuration:
<VirtualHost *:*>
RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME}
</VirtualHost>
<VirtualHost *:80>
ServerName my.public.domain
Redirect / https://my.public.domain/
</VirtualHost>
<VirtualHost *:443>
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:50001/
ProxyPassReverse / http://127.0.0.1:50001/
ServerName my.public.domain
ErrorLog ${APACHE_LOG_DIR}my-app-error.log
CustomLog ${APACHE_LOG_DIR}my-app-access.log common
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/my-cert/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/my-cert/privkey.pem
</VirtualHost>
In UseUrls method i have http://localhost:50001 configured as main URL, and this is redirected by Apache to HTTPS #443.
It works as charm, however I see this in logs:
warn: Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware[3]
Failed to determine the https port for redirect.
In my configuration Apache handles https traffic, BTW, I can't communicate my app with Apache locally over HTTPS, it just doesn't work. I also think it's pointless to encrypt local internal traffic.
Unfortunately my solution requires some hacking to work 100% properly - I need to provide my public site URL in my app configuration - otherwise the app doesn't know what it's external address is. I mean - I build some links manually, because this is the core of my question - I don't know where the framework would keep such information. For example NavigationManager thinks my site URL is "http://localhost:50001", so if I need absolute URL in my app I can't use NavigationManager directly, I need to "manually" create the URL in app.
Links generated by Identity have "http" instead of "https", but it works because apache redirects everything to https.
Is there a way (and HOW) to do it more properly - a mean to officially tell the AspNET.Core it has specific external URL?
Where you have ServerName my.public.domain, use the following:
For port 80:
ServerName http://my.public.domain:80
For port 443:
ServerName https://my.public.domain:443

Apache reverse proxy and Wicket CsrfPreventionRequestCycleListener

Since integrating CsrfPreventionRequestCycleListener into our Apache Wicket (7.6.0) application, we have a problem operating the application behind an Apache reverse proxy.
Our configuration terminates SSL at Apache, and the reverse proxy passes the requests via http to our Wildfly 10 application server. This allows us to offload TLS/SSL among other things.
But since adding the CsrfPreventionRequestCycleListener, we are seeing the following in the server.log file and connections are aborted:
[org.apache.wicket.protocol.http.CsrfPreventionRequestCycleListener]
(default task-12) Possible CSRF attack, request URL:
http://example.com/example/portal/wicket/page,
Origin: https://example.com, action: aborted with error
400 Origin does not correspond to request
The problematic Apache config:
<VirtualHost example.com:443>
ServerName example.com
LogLevel debug
SSLEngine On
SSLCertificateFile /var/example/example.com/signed.crt
SSLCertificateKeyFile /var/example/example.com/domain.key
SSLCACertificateFile /var/example/example.com/intermediate.pem
SSLProtocol +TLSv1.2 +TLSv1.1 +TLSv1
SSLOpenSSLConfCmd DHParameters "/usr/local/apache2/1024dhparams.pem"
SSLProxyEngine on
ProxyPass / http://localhost:8390/ timeout=600
ProxyPassReverse / http://localhost:8390/ timeout=600
ProxyPreserveHost On
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Credentials "true"
Header edit Location ^http(\:\/\/.*)$ https$1
We found a solution using http2 but would prefer one without http2 (for reasons, see in https://http2.pro/doc/Apache).
The working Apache configuration using http2
<VirtualHost example.com:443>
ServerName example.com
LogLevel debug
SSLEngine On
SSLCertificateFile /var/example/example.com/signed.crt
SSLCertificateKeyFile /var/example/example.com/domain.key
SSLCACertificateFile /var/example/example.com/intermediate.pem
SSLProtocol +TLSv1.2 +TLSv1.1 +TLSv1
SSLOpenSSLConfCmd DHParameters "/usr/local/apache2/1024dhparams.pem"
SSLProxyEngine On
ProxyPreserveHost On
# Settings for http2 communication
Protocols h2 http/1.1
ProxyPass / https://localhost:8754/ timeout=600
ProxyPassReverse / https://localhost:8754/ timeout=600
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
SSLProxyCheckPeerExpire off
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Credentials "true"
# Header edit Location ^http(\:\/\/.*)$ https$1
</VirtualHost>
Can anyone help us create a valid apache reverse proxy configuration that works with the CsrfPreventionRequestCycleListener without the http2 module?
I think I had a similar issue here and solved it just now. I think you might have solved your issue by now but maybe anyone else is falling over this topic.
You might want to look into a network dump to verify the problem. For me, apache sent requests to the locally running service (your case to http://localhost:8754) while some request headers were still referring the public name https://example.com. This was detected as a security risk and the connection refused by the underlying service.
I made sure, that mod_headers was enabled in apache and added the line
RequestHeader edit Referer "https://example.com" "http://localhost:8754"
After that no more references to anything related to example.com was in my tcp dumps and the connection was opened successfully.
You might need to adopt according to your setup (maybe you need multiple headers corrected or something similar). I cannot try it out at the moment.

Reverse proxy for external URL - Apache

I configured my apache so that it can forward my requests to external URL like google.com, but the reverse proxy doesn't work.
<VirtualHost *:443>
ServerName authtest.com
ProxyRequests Off
ProxyPreserveHost On
<Proxy *>
Order allow,deny
Allow from All
</Proxy>
<LocationMatch "/google">
ProxyPass https://www.google.com/
ProxyPassReverse https://www.google.com/
</LocationMatch>
</VirtualHost>
Is it possible for me to reverse proxy external websites?
Is it possible for me to reverse proxy external websites?
Yes but with significant downsides.
Note: when I tried your configuration, I got SSL Proxy requested for [...] but not enabled [Hint: SSLProxyEngine] in the logs so I added SSLProxyEngine on.
Host issue
When you make a HTTP/1.1 request to a server, you automatically add the hostname in the request. When you proxy them, you have two possibilites:
[browser] --(Host: authtest.com)--> [apache proxy] --(Host: authtest.com)--> Google
or
[browser] --(Host: authtest.com)--> [apache proxy] --(Host: google.com)--> Google
The first one is what you get with ProxyPreserveHost On. Google servers won't handle requests for authtest.com, you should remove this line.
Even in the second case, you can have issues. ProxyPassReverse will handle redirects but only for the given domain: I'm in France, google.com redirects me to google.fr (a different domain) and the reverse proxy doesn't rewrite the redirect.
An other issue is the referer: if a service sees requests for images/css/js coming from a different web site it may consider it as bandwidth leeching and block them. Now, you need to rewrite the html of the response too (mod_proxy_html will help but it's not a silver bullet).
Path issue
In your example, you proxy <authtest>/google to <google>/. Like above, you need to rewrite the html: absolute links/resources won't work unless your server adds /google everywhere. Same for relative links/resources (but with more edge cases). If you owned the backend server, you could have checked urls in html/css/js files. Here, if the url is built dynamically in the browser using js you can't do anything.
If you can proxy / to / (or /whatever to /whatever) you will avoid a lot of issues here.
Chech this GIT Repo
I forked a GIT Repo and customized it to work with scenario:
[browser] --(Host: google.local)--> [apache proxy] --(Host: google.nl)--> Google
The Apache config as follows:
<VirtualHost *:80>
ServerName google.local
SSLProxyEngine on
ProxyRequests Off
<Proxy *>
Order allow,deny
Allow from All
</Proxy>
ProxyPass / https://www.google.nl/
ProxyPassReverse / https://www.google.nl/
ErrorLog /var/log/apache2/google.local-error.log
CustomLog /var/log/apache2/google.local-access.log combined
</VirtualHost>

Multiple ProxyPassReverse for a Virtual Host with identical URLs

We have a situation where we have one JBoss application that is being proxied by two Apache paths as a Virtual Host below:
<VirtualHost *:80>
ServerName localhost1
ProxyPass /abba/ http://localhost:8080/app/
ProxyPass /babba/ http://localhost:8080/app/
ProxyPassReverse /abba/ http://localhost:8080/app/
ProxyPassReverse /babba/ http://localhost:8080/app/
</VirtualHost>
The routing of /abba/ and /babba/ need to go to the same application - going forward we are using rewrites to add some parameters that the application uses to configure itself based on whether /abba/ or /babba/.
However when the application sends a redirect the ProxyPassReverse does not work as access sayfrom /babba/ gets redirected to /abba/.
I understand the reason as it's the same application - however is there are way of configuring Apache to support two difference routes (ProxyPass and ReverseProxyPass) to the same application.
Many Thanks
Have you tried duplicating the VirtualHost and changing the duplicate to server name "localhost2"?