IIS 7.5 and Web API 2 PUT/DELETE Requests - iis

This seems to be a common problem but I've troubleshot all the other techniques people are getting and had no luck, so here goes:
I'm running WebAPI2 along with IIS7.5 on Windows Server 2010. In development my PUT/DELETE requests started working after I added the PUT/DELETE Handlers in HTTP Handlers of IIS. However, once I rolled to prod and applied the same changes I got no such luck. Heres my setup:
WebConfig
Server:
Requests:
Request URL:http://dev.myserver.com/myapp/api/apps/76a09a7b-0750-4045-a3ce-696df0ff179c
Request Method:PUT
Status Code:405 Method Not Allowed
405 - HTTP verb used to access this page is not allowed.
The page you are looking for cannot be displayed because an invalid method (HTTP verb) was used to attempt access.
Response Headers:
Allow:GET, HEAD, OPTIONS, TRACE
Content-Length:1293
Content-Type:text/html
Date:Thu, 21 Nov 2013 15:43:44 GMT
Server:Microsoft-IIS/7.5
X-Powered-By:ASP.NET
Obliviously its mad because that verb is not acceptable but the configuration shows that it is. I saw another article talking about removing the WebDav Module from the Modules in IIS, however, once I did that I got a 500 Internal Server Error ( probably because its needed hehe ). Like I said this code is working correctly in dev so I'm not sure what the disconnect is.

Seems if I missed the 'HttpHandler' remove of WebDav. The following works:
<system.webServer>
<modules>
<remove name="WebDAVModule" />
</modules>
<handlers>
<remove name="WebDAV" />
</handlers>
</system.webServer>

Related

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

Hosting ASP.NET Core to IIS returns Internal Server error

Deployed ASP.NET MVC Core 1.1.1 on Windows 2012 Server R2. Followed this ASP.NET article (installed DotNetCore.1.0.5_1.1.2-WindowsHosting bundle etc). App runs fine as localhost on the server if we follow the following steps:
In cmd from root dir of the app, ran: dotnet MyWebapplication.dll
Noticed that application is running and waiting for responses on localhost:5000.
Opened the browser on the host server and navigated to: http://localhost:5000
Home page opened as expected
But when we navigate to the http://IP Address/MyWebapplication on a different desktop on the same network, we get the 500 - Internal Server Error
NOTE: We tested that if we host a simple web app (not ASP.NET Core) with just one Index.html page on IIS, we can access the app from another machine on the same network via, say, http://IP Address/MySimpleHtmlApp. So issue seems to be related to something on ASP.NET Core deployment on IIS. Question: What we may be missing and how to resolve it?
UPDATE:
The IIS has default port 80 that is open. When we run the app directly from IIS on the server (i.e., http://localhost:80/MyWebapplication) it gives the following error:
HTTP Error 500.19 - Internal Server Error
The requested page cannot be accessed because the related configuration data for the page is invalid.
Detailed Error Information:
Module IIS Web Core
Notification BeginRequest
Handler Not yet determined
Error Code 0x8007000d
Config Error
Config File \\?\D:\TestApp\PublishOutput\web.config
Requested URL http://localhost:80/TestWebApp
Physical Path D:\TestApp\PublishOutput
Logon Method Not yet determined
Logon User Not yet determined
Config Source:
-1:
0:
Following is the web.config file (created by VS2017):
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="dotnet" arguments=".\TestWebApp.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" />
</system.webServer>
</configuration>
<!--ProjectGuid: 21c38c6d-7aff-4624-b310-a0f5f766b461-->
Well, first off, you're not really deploying this to IIS; you're self-hosting. If you want to run it under IIS, you need to create a site in IIS for it, drop in the published code, and configure the App Pool to run "No Managed Code". Then, you can pull up the site under whatever bindings you've added for it in IIS.
Second, your test case of a "simple website", it not utilizing a non-standard web port (it's using 80), while your ASP.NET Core app is (5000). This may very well be due to a firewall you have running, as most firewall appliances will block access by default to any non-standard port. You'll either need to open up a rule for that port on your firewall or host it on port 80, like you're doing with your "simple website".

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" />

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.

403 forbidden with socket.io and iisnode

I have a node.js socket.io server application that I have just moved to IISNode in IIS 8.5 in Windows Server 2012. It is set up to use https.
It all works fine when I browse locally but when I try to access it with a full domain name, I get error 403 (forbidden) when I try to open the web socket connection.
The same problem happens with my real application as happens with the Dante Devine Comedy socket.io sample. Tomasz Janczuk iisnode Dante sample
The standard sample when browsed to with
https://localhost/dante/server-socketio.js
or with
https://interfaces.xxxxxx.co.uk/enable/testing/dante/server-socketio.js
locally on the same server, opens the socket.io web socket connection with
var client = io.connect('https://localhost', { resource: 'dante/socket.io' });
and works correctly producing the following network capture:
Obviously the above does not work when accessed externally (not localhost) so I change the web socket connection to
var client = io.connect('https://interfaces.xxxxxx.co.uk/enable/testing',
{ resource: 'dante/socket.io' });
and this fails with an error 403 as follows:
my web.config is the same as the one supplied with the Dante sample and contains:
<handlers>
<add name="iisnode-socketio" path="server-socketio.js" verb="*" modules="iisnode" />
</handlers>
<rewrite>
<rules>
<rule name="LogFile" patternSyntax="ECMAScript">
<match url="socket.io"/>
<action type="Rewrite" url="server-socketio.js"/>
</rule>
</rules>
</rewrite>
<webSocket enabled="false" />
I'm new to node.js, socket.io and iisnode and a bit of a novice with IIS so this could be a simple iis/web site/https problem and not related to iisnode.
I'd appreciate it if anyone has any suggestions.
John.
Following CuriousGuy's suggestion, I now get the following network capture showing that the switch to web socket protocol has not happened. The actual error shown is
WebSocket connection to 'wss://interfaces.xxxxxx.co.uk/enable/testing/dante/socket.io/1/websocket/ANNcSf7ghQp66nwSS-7P'
failed: Error during WebSocket handshake: Unexpected response code: 200
I tried changing the server io.set from
io.set('resource', '/dante/socket.io');
to
io.set('resource', '/enable/testing/dante/socket.io');
but that was clearly a mistake because I then get an error that io is undefined which seems a little weird.
If I examine the network traffic in fiddler I see:
and the following error message in fiddler when I tap the last network line:
iisnode encountered an error when processing the request.
HRESULT: 0x6d
HTTP status: 500
HTTP reason: Internal Server Error
You are receiving this HTTP 200 response because
system.webServer/iisnode/#devErrorsEnabled
configuration setting is 'true'.
The server stderr log shows:
debug: served static content /socket.io.js
debug: client authorized
info: handshake authorized o7WE52TfMWPxFoJIZFJJ
debug: setting request GET /dante/socket.io/1/websocket/o7WE52TfMWPxFoJIZFJJ
debug: set heartbeat interval for client o7WE52TfMWPxFoJIZFJJ
warn: websocket connection invalid
info: transport end (undefined)
debug: set close timeout for client o7WE52TfMWPxFoJIZFJJ
debug: cleared close timeout for client o7WE52TfMWPxFoJIZFJJ
debug: cleared heartbeat interval for client o7WE52TfMWPxFoJIZFJJ

Resources