Tomcat RemoteIpValve with IIS 7 via ARR - iis-7.5

I'm trying to setup IIS 7.5 as reverse proxy to connect to Tomcat 7 via ARR 3.
For some reason when IIS forwards the request, the x-forwarded-for header contains the remote port, so instead of showing something like: 123.124.125.126 I see 123.124.125.126:54321
Unfortunately that does not work with RemoteIpValve, which expects the IP address only.
Is there a way to remove the port from IIS? or in RemoteIpValve?
Update: I tried running the command below and I can see that it updated applicationHost.config but I still see the port number (restarted IIS):
appcmd.exe set config -section:system.webServer/proxy /includePortInXForwardedFor:"false" /commit:apphost
Thanks!

I ended up using the following workaround:
On IIS, in %System32%/inetsrv/config/applicationHost.config I added the following snippet at system.webServer/rewrite/globalRules/rule [name=ARR*]:
<severVariables>
<set name="HTTP_X_REMOTE_ADDR" value="{REMOTE_ADDR}" />
</severVariables>
Then I specified that name to the RemoteIpValve in Tomcat's server.xml
<Valve className="org.apache.catalina.valves.RemoteIpValve" remoteIpHeader="x-remote-addr" />
To use the newly added header instead of X-Forwarded-For

Related

How to execute OpenTest thru Apache reverse proxy along with other applications

First some context
We have an Ubuntu Server 18.04 LTS server running on Azure
Our company security policies only allows for ports 80 and 443 to be accessed thru HTTP/HTTPS
Any applications such as Jenkins or NodeJS ones running on other ports should use a reverse proxy thru Apache
The same server already has Jenkins running on port 8080 and Jenkins itself can be configured to run using what they call a "--path" parameter which makes it accessible thru URL http://localhost:8080/jenkins, hence reverse proxy is pretty straight forward to configure as anything going to "/jenkins" can just be pass to http://localhost:8080/jenkins, current Apache config (which is working for Jenkins) as follows:
# Jenkins
ProxyPass /jenkins http://localhost:8080/jenkins nocanon
ProxyPassReverse /jenkins http://localhost:8080/jenkins
ProxyRequests Off
AllowEncodedSlashes NoDecode
<Proxy http://localhost:8080/jenkins*>
Order deny,allow
Allow from all
</Proxy>
The problem we are facing
So, for running OpenTest, we have to install it as a npm package which can then be executed by running opentest server command, it will start the application on port 3000 by default http://localhost:3000 but it is possible to change the preferred port as well thru configuration https://getopentest.org/reference/configuration.html#server-configuration
The problem is that we need to re-route anything, let's say going to "/opentest" to the opentest server app but that doesn't work for all static assets, api urls, etc... since the app is just running on port 3000 http://localhost:3000 but doesn't seems to have something like the Jenkins' "--path", so we can't just mimic the same reverse proxy we have for Jenkins; the idea would be to have opentest in path "/opentest", something like http://localhost:3000/opentest.
We were not able to find any OpenTest configuration that allows me to do something like http://localhost:3000/opentest and we are new to pm2 so we can't tell if it is possible to use pm2 to to run the OpenTest application in a "path" or some sort of "local known application domain" which we could use to re-route the reverse proxy to.
Any thoughts, ideas, workarounds or solutions are welcome; we might be taking the wrong approach here so we would also appreciate any insights in that regard.
Thanks!
Starting with version 1.2.0, you can use the urlPrefix configuration parameter in server.yaml to accomplish this:
#...
urlPrefix: /opentest

IIS ARR Reverse proxy running in Docker under Azure VM returns 404

Using an Azure Server Core 2019 VM I've set up a number of docker containers with ISS/ARR 3.0 as the reverse proxy.
When I access the host url: "http://[hostname]/deploy" i expect the RP to redirect to http://[docker ip]:81
81 is the exposed port of the separate internal docker container that "deploy" runs on. FYI: This is mapped to host port 1322... accessing hostname:1322 via an external browser works fine.
(I've also tried using a rewrite rule to [hostname]:1322 and [docker ip]:1322)
No matter what i do, I always get 404 (not found)
I can't figure out why. Is there something in Azure itself messing this up? The only networking I appear to have available to docker in windows is NAT (via docker network ls). I've got the correct IP address of the target docker container via "docker inspect [container]" but I think this is the IP address as exposed to the host, not that can be seen by other containers running on the host.
How do I know what the internal docker IP is that is available to other running docker containers for the ARR rule (or is there another way to set this up so it knows the rule dynamically?)
my ARR web.config is:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="deploy" stopProcessing="true">
<match url="^(.*)/deploy" />
<action type="Rewrite" url="http://172.23.60.148:81" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
My reverse proxy docker file is:
FROM mcr.microsoft.com/windows/servercore/iis
# Download and install the required URL rewrite and Application Request Routing modules. Clean up after!
ADD http://go.microsoft.com/fwlink/?LinkID=615137 /install/rewrite_amd64.msi
ADD http://go.microsoft.com/fwlink/?LinkID=615136 /install/ARRv3_setup_amd64_en-us.msi
RUN msiexec.exe /i C:\install\rewrite_amd64.msi /qn /log C:\ms_install.log & \
msiexec.exe /i C:\install\ARRv3_setup_amd64_en-us.msi /qn /log C:\arr_install.log & \
rd /s /q c:\install
# Enable proxy feature for IIS. Allows us to act as a reverse proxy
RUN .\Windows\System32\inetsrv\appcmd.exe set CONFIG -section:system.webServer/proxy /enabled:"True" /commit:apphost
# The web config should contain our routing to other containers
ADD ./web.config /inetpub/wwwroot/web.config
So, it turns out that the problem is not docker at all but ARR.
When you add the rewrite rule, it's logical to expect this "^(.*)/deploy" to be the match criteria, i.e. "ending with /deploy". The rewrite rule tester in IIS even works correctly when you try it out.
Turns out, IIS doesn't pass the / to the rewrite rules engine. It only passes the text "deploy"... so the rule never matches and it then passes it onto the underlying IIS site instead of the the target... and of course /deploy doesn't exist in the underlying site, hence the 404.
Related ARR issues here
URL rewrite in IIS 8.5 is not working I'm getting 404 instead
Url Rewrite in IIS get 404

Tomcat Virtual Host to prevent Improper-Input-Handling attack

I'm currently on the process of trying fix a site vulnerability, basically it is one type of the "Improper Input Handling" attack.
Let's say my website is www.mywebsite.com
and there is hacker's website www.hacker.com
whenever there is a request send to www.mywebsite.com with modified "Host" header point to www.hacker.com, my site will create a redirect to www.mywebsite.com along with whatever the url it was.
e.g.
Normal:
Host: www.mywebsite.com
GET www.mywebsite.com/get/some/resources/
Reponse 200 ok
Hack:
Host: www.hacker.com (#been manually modified)
GET www.mywebsite.com/get/some/resources/
Response 302
Send another Redirect to www.hacker.com/get/some/resources
My website is running on Tomcat 7, I tried some solution with set up the virtual host by point the unknown host to a defaultlocalhost which suppose to do nothing. but it still send the redirect for some reason.
Here attached is my server.xml host configure:
<Engine name="Catalina" defaultHost="defaultlocalhost" jvmRoute="jvm1">
<Host name="www.mywebsite.com" appBase="webapps"
unpackWARs="true" autoDeploy="false" deployOnStartup="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
<Host name="defaultlocalhost" >
</Host>
So, my question is, Am I on the right track to prevent this kind of attack ? If yes, what I did wrong that still not working? (The ultimate goal is, if it is not the legit Host that been passed in, the request should be discard/ignored/return 404 but not redirect with 302)
Thank you in advance.
More references about the attack here :
http://www.skeletonscribe.net/2013/05/practical-http-host-header-attacks.html
http://projects.webappsec.org/w/page/13246933/Improper%20Input%20Handling
Oh well, end up answer my own question.
After join the Tomcat user mailing list (subscribe email address: users#tomcat.apache.org).
There is the guy named Andre helped me get this resolved:
basically what I did wrong is missing appBase in my defaultlocalhost
<Host name="defaultlocalhost" appbase="whatever" >
</Host>
The above configure successfully returned 404 status whenever a illegal request was been send. the reason is that whenever you don't set the appbase it always default to webapps so it essentially didn't do anything with my original configure.
Hope this can help anyone who had similar issue.
Update 7/10/2020
A 403 can be returned by adding in a RemoteAddrValve and blocking all ip's. The example is based on Tomcat 9.
http://tomcat.apache.org/tomcat-9.0-doc/config/host.html#Request_Filters
<Host name="defaultlocalhost" appbase="whatever">
<!-- deny all remote addresses to this host -->
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
deny="\d+\.\d+\.\d+\.\d+"/>
</Host>
Although it didn't exist at the time this question was asked, Tomcat 7.0.87 introduced a new property allowHostHeaderMismatch on the connector (cf. documentation). If you set it to false (default since Tomcat 9.0), Tomcat will return a 400 Bad Request error whenever the Host header does not match the request line:
<Connector port="8080" allowHostHeaderMismatch="false" />

Configuring IIS as reverse-proxy for Keycloak

I'm using Keycloak 2.3.0 version, standalone mode, server. I configured IIS URL Rewrite for local Keycloak server running on localhost:8080.
The problem is that there is no way to specify base url in Keycloak, instead Keycloak tries to detect its own host/port and always appends port number (8080) to redirects.
I fixed everything except 'auth-server-url' in config json. Is there any way to get it working?
I've been running Keycloak behind a reverse-proxy for some time. The key is:
to have it configured properly in standalone.xml - HTTPS proxy settings for mydomain.com/sso settings follow:
<http-listener name="default"... -> <http-listener name="default" socket-binding="http" proxy-address-forwarding="true" redirect-socket="proxy-https"/>
<socket-binding name="http"... -> <socket-binding name="proxy-https" port="443"/>
<web-context>auth... -> <web-context>sso</web-context>
to run it on the same context path as the proxy is. Eg. mydomain.com/keycloak -> localhost:8080/keycloak
to access Keycloak admin console from the non-local address for the first time - it generates some of its settings based on this first access

Error: listen EACCES 0.0.0.0:80 Node on azure server (Windows server 2012 r2)

I stopped the World Wide Web Publishing Service and changed the Startup Type to Disabled and ran as administrator to start the website but received the EACCES.
Is this a permissions error? I have read that running the website with sudo on linux / unix fixes this, but what about on windows?
EDIT: I ended up using iisnode as I could not resolve the EACCES error on port 80. Here are the steps I used to get my node server running on iis through iisnode module:
*Install iisnode (wherever you want);
*Install 'URL Rewrite' plugin for iss;
*Create new site;
*Create web.config file with:
handler mapping for iisnode on server file with path to server file;
rewrite url rule that any request to url goes to server file;
debugging and logging (with path to log file destination) set to true;
(Please find an example web.config file at the bottom of this post)
*Give SERVER/IIS_IUSRS write permissions to the directory / virtual directory found in iis of the site;
*Create local binding;
*Create external binding with *:80 as port;
*Make sure that node's http listener is set to listen on process.env.PORT as iisnode will set this environment variable to 80 for http requests;
Example web.config file in the root folder and assuming that the node server (in this case it will be called app.js) is also just in the root folder too.
<configuration>
<system.webServer>
<!--Tells iis that app.js is to be handled by iisnode module-->
<handlers>
<add name="iisnode" path="app.js" verb="*" modules="iisnode" />
</handlers>
<!--Url rewrite rule that anything coming to any url of within site goes through app.js-->
<rewrite>
<rules>
<rule name="toNode">
<match url="/*"/>
<action type="Rewrite" url="app.js"/>
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
EDIT: For the most part, I followed this tutorial:
https://www.youtube.com/watch?v=JUYCDnqR8p0
If you want to run node app on port 80, then you have to run it with sudo privileged account.
For windows, probably, restarting iis node can resolve the issue.
run node.js webbapp on 80 port on windows
I want to reproduce the issue via create an Azure VM using the image Windows Server 2012 R2 DataCenter from gallery, but failed that the node app works on port 80.
Per my experience, there are some steps you can try to resolve the issue.
Select the Command Prompt and right click to select the option Run as administrator to startup the cmd for running node or others as administrator.
Command netstat -ao to display the all listening ports and their PID, then find the one of Local Address 0.0.0.0:80 and command taskkill /PID <PID> /F to forcefully terminate the process ran on port 80.
Try to command node app.js again.
You can also generate a Node.js Azure Webapp from Azure CLI.
Install Azure CLI with NPM:
c:\> npm install azure-cli -g
Login to your azure account:
c:\> azure login
Change mode to asm
c:\> azure config mode asm
From your local git repository, create an azure webapp (named yoursite):
c:\git\yoursite> azure site create --git yoursite
This will generate add all the necessary settings in the issnode.yml file.
Commit with git:
c:\git\yoursite> git add . && git commit -m "initial commit"
Push the modifications to the azure server:
c:\git\yoursite> git push https://yourlogin#yoursite.scm.azurewebsites.net:443/yoursite.git
Azure will add the node dependencies and run your site on port 80.

Resources