Req.protocol is always http and not https - node.js

I have recently migrated a NodeJS app using the Express web server from one hosting provider to another.
Since the switch, all of my req.protocol are returning as HTTP instead of HTTPS. I have configured the SSL certificates on the new host and it is forcing SSL with .htaccess file.
I have always had the trust proxy enabled in my application.
app.enable('trust proxy)';
But, I have tried disabling this but it did not solve my problem.
The request header I am receiving with trust proxy enabled:
{ host: '127.0.0.1:58535',
'upgrade-insecure-requests': '1',
'user-agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36',
accept:
'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*
/*;q=0.8,application/signed-exchange;v=b3',
'sec-fetch-site': 'none',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'en-US,en;q=0.9',
cookie:
'_ga=GA1.2.1627492895.1565633625; _gid=GA1.2.952960627.1565633625;
_hjid=aa79d062-c91e-483d-8654-e2d11b4b8707; _hjIncludedInSample=1',
'if-none-match': 'W/"7d4b-dYhPiTxJki+OCl9FjTfsJQnUkSM"',
'x-forwarded-for': 'X.X.X.X',
'x-forwarded-host': 'example.example.com',
'x-forwarded-server': 'example.example.com',
connection: 'close' }
I am not using NGINX. Why is my app not detecting https as the protocol?

After some debugging, it seemed to be a configuration problem with the Apache web server. The web host I was using had some custom configuration which made it difficult to modify the apache config without breaking after services running on the server.
In the end, I decided to learn about Nginx and implement that as a web proxy for my nodeJS application. using app.enable('trust proxy)'; in my code allowed the correct protocol to be passed to the app.

Related

AngularJS app sign-in function 404 error, xhr.send(post || null)

An old web app that uses Angular, gulp and coffee-script, and was running whit forever(NPM package).
When I click the sign-in button on the page, the page will refresh and show a 404 error, an apache access log saying
"POST /api/user/sign-in HTTP/1.1" 404 488 "http://localhost/sign-in" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36"
Need help, thanks
We didn't change any code or env, only use Nginx Proxy manager to take the place of Kemp load balancer.
I got the apache log because I copied all stuff and the database running it on localhost.

Specifying proxy for http-proxy-middleware

I have a nodeJS project for a front-end that connects to multiple micro services.When we do final deployments we actually deploy the built JS and HTML in a WAR file along with the backend.
However, for development we use the http-proxy-middleware so we are able to do quick changes and edits on the front-end and see the results.
Today though, I would like to be able to see the connections leaving NODE-JS and going towards our microservices.
Specifically, I want to tunnel them through fiddler ( which is an http proxy usually running on port 8888 ).
Does anyone know to do this?
I tried setting e.g. the following but it doesn't affect the outgoing connection:
npm config set proxy http://localhost:8888
npm config set proxy http://localhost:8888 is used to configure NPM to download packages through a proxy.
You will need to connect to fiddler's HTTP proxy instead of your usual backend, with the relevant HTTP headers for proxying.
So a request would look something like
http.get ({
host: '127.0.0.1',
port: 8888,
path: 'http://actual.backend/url'
}, function (response) {
console.log (response);
});
Well, the answer to my problem is to use fiddler as a reverse proxy:
https://docs.telerik.com/fiddler/Configure-Fiddler/Tasks/UseFiddlerAsReverseProxy
I came across it by accident partly. I thought maybe I can't intercept all requests, but I could set my endpoint as being fiddler.
I did that, and saw a response in fiddler from the Fiddler Echo Service.
It basically displays a page similar to:
Fiddler Echo Service
PUT /abc-service/initialize HTTP/1.1
accept-language: en-AU,en;q=0.9,el;q=0.8,en-NZ;q=0.7,en-US;q=0.6,en-GB;q=0.5
accept-encoding: gzip, deflate, br
accept: */*
postman-token: 0466cca5-21f9-67ab-be05-5227ef667fe4
user-agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36
origin: chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop
cache-control: no-cache
content-length: 0
connection: close
host: localhost:8889
X-Tenant-Id: abc
X-Forwarded-Proto: http
X-Forwarded-Force-Http-Protocol: true
X-Forwarded-Prefix: abc-service
This page returned a HTTP/200 response
Originating Process Information: node:15044
--------------------------------------------------------------------------------
•To configure Fiddler as a reverse proxy instead of seeing this page, see Reverse Proxy Setup ( https://docs.telerik.com/fiddler/Configure-Fiddler/Tasks/UseFiddlerAsReverseProxy )
•You can download the FiddlerRoot certificate

How to send POST request to https without causing SSL certificate error from python3

Here's the thing , I have been trying to send POST request to LOGIN to my college wifi page from within python but I am getting SSL certicate error . The POST request works fine from POSTMAN extention of chrome.
Here is how the request looks like when I use the chrome'e debugger to see the POST requests
Request URL:https://112.133.253.2:8090/login.xml
Request Method:POST
Status Code:200 OK
Remote Address:112.133.253.2:8090
Referrer Policy:no-referrer-when-downgrade
POST /login.xml HTTP/1.1
Host: 112.133.253.2:8090
Connection: keep-alive
Content-Length: 72
Origin: https://112.133.253.2:8090
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: */*
Referer: https://112.133.253.2:8090/httpclient.html
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
I found that the Problem was in specifying 'http' in the post request url , which should have been https .
When I use https however , I get the python's SSL certificate error .
I have tried giving verify=False parameter with no luck . I have also tried giving path to certificate like this :-
resp = S.post("https://112.133.253.2:8090/login.xml" ,
data = data ,
verify = "/etc/ssl/certs/ca-certificates.crt") ;
But nothing works .
How is the extension of postman working without giving SSL certificate errors ? How can I fix this issue to send the requests from Python itself ?
Try disabling warnings like this:
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
Hope it helps.

Working Exploit for tomcat vulnerability : JSP Upload Bypass CVE-2017-12617

https://lists.apache.org/thread.html/3fd341a604c4e9eab39e7eaabbbac39c30101a022acc11dd09d7ebcb#%3Cannounce.tomcat.apache.org%3E
I have a tomcat 6.x, 7.x and 8.x and Jboss 7.2.x AS server running on windows. I created a web application under the webapps directory. I modified $TOMCAT_HOME/conf/web.xml and set the readonly parameter to false(by default, it is true). Then, I ran the exploit https://www.exploit-db.com/exploits/42966/ -- which is a python script that tries to upload a payload using HTTP PUT.
I ran the following command line :
python 42966.py -u http://localhost:9292/ExploitTest
I am getting a
1) Http 404 status(resource not found) from tomcat 8.0.x,
2) Http 400 status(bad request) from tomcat 6.x and
3) Http 400 status from tomcat 7.x.
I was expecting that running the above python exploit would result in HTTP 201 (newly created resource) in the tomcat server. What's wrong with the exploit ? OR did I not setup tomcat correctly for the vulnerability ? Is there a curl or java based or any other working exploit for this vulnerability that I can use to verify that my server is indeed vulnerable or not ?
Found the answer on https://www.peew.pw/blog/2017/10/9/new-vulnerability-same-old-tomcat-cve-2017-12615. Originally, the request is at https://bz.apache.org/bugzilla/show_bug.cgi?id=61542.
I used Burp Suite to craft the POC request per above link
PUT /1.jsp/ HTTP/1.1
Host: 192.168.3.103:8080
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://192.168.3.103:8080/examples/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4,zh-TW;q=0.2
Cookie: JSESSIONID=A27674F21B3308B4D893205FD2E2BF94
Connection: close
Content-Length: 26
<% out.println("hello");%>
This does the trick!

Websockets reverse proxy in IIS 8

I'm attempting to connect to a websockets server (websockify) through a reverse proxy on IIS. The IIS and websockets server reside on the same physical server (Windows Server 2012 R2, IIS 8.5, ARR 3, Websockets enabled). I've seen a few questions about this and it's suggested this should work with IIS 8 and ARR 3, but no actual solutions as yet. I have some experience with http/https reverse proxies in IIS, but this is my first attempt working with websockets.
For example:
The original url:
ws://10.2.1.10/websockify
The reverse proxy needs to translate this to:
ws://10.2.1.10:5901/websockify
Overly general sample rule in web.config:
<rewrite>
<rules>
<rule name="WS reverse proxy" stopProcessing="true">
<match url="(.*)" />
<conditions> <add input="{CACHE_URL}" pattern="^(.+)://" />
</conditions>
<action type="Rewrite" url="{C:1}://10.2.1.10:5901/websockify"/>
</rule>
</rules>
</rewrite>
Per the Failed Request Trace, the url appears to be translated, but for some reason it doesn't reach the websocket server at 10.2.1.10:5901.
The end goal is to incorporate noVNC/websockify to provide browser based client access to multiple VNC servers on the network. Any help understanding how to reverse proxy the websockets is appreciated.
I had been trying to accomplish this same thing on IIS 8.5 with ARR 3.0, and eventually found the problem. According to Microsoft's Erez Benari, this is possible:
WebSocket support requires the WebSocket feature to be installed on IIS, but does not require any other configuration or action. Install the feature using the Server Manager Add Roles and Features, and once that is complete, ARR 3.0 will handle the requests appropriately.
As a test, I set up a Node.js server for WebSocket:
const WebSocketServer = require('ws');
const wss = new WebSocketServer({ port: 3011 });
function sendWSMessage(msg) {
wss.clients.forEach((client) => {
client.send(msg);
});
}
setInterval(function() {
sendWSMessage('hello client');
}, 3000);
Along with a simple test page:
var websock = new WebSocket('ws://localhost:3011');
websock.onmessage = function (event) {
console.log(event.data);
};
websock.onopen = function (event) {
websock.send("hello server");
};
Then, I set up an ARR reverse proxy on my local machine, with the following in a web.config file of a "wstest" directory on localhost:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="WebSocketTestRule" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{CACHE_URL}" pattern="^(.+)://" />
</conditions>
<action type="Rewrite" url="{C:1}://localhost:3011/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
This should forward all traffic for //localhost/wstest to a Node.js server on port 3011. The Node server works when I directly connect to it via ws://localhost:3011. When I try to connect through the proxy via ws://localhost/wstest, the request makes it through to the Node.js server, the upgrade occurs, and the connection is made.
Chrome sends:
GET ws://localhost/wstest HTTP/1.1
Host: localhost
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: file://
Sec-WebSocket-Version: 13
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Sec-WebSocket-Key: 4ufu8nAOj7cKndASs4EX9w==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
The Node.js server receives:
cache-control: no-cache
connection: upgrade
pragma: no-cache
upgrade: Websocket
accept-encoding: gzip, deflate, sdch
accept-language: en-US,en;q=0.8
host: localhost:3011
max-forwards: 10
user-agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36
origin: file://
sec-websocket-version: 13
sec-websocket-key: fBkTwAS9d/unXYKDE3+Jjg==
sec-websocket-extensions: permessage-deflate; client_max_window_bits
x-original-url: /wstest
x-forwarded-for: [::1]:54499
x-arr-log-id: a0b27458-9231-491d-b74b-07ae5a01c300
The Node.js server responds with:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-Websocket-Accept: yep8mgQACAc93oGIk8Azde4WSXk=
Sec-WebSocket-Extensions: permessage-deflate
And finally Chrome receives:
HTTP/1.1 101 Switching Protocols
Upgrade: Websocket
Sec-WebSocket-Accept: CBSM8dzuDoDG0OrJC28nIqaw/sI=
Sec-WebSocket-Extensions: permessage-deflate
X-Powered-By: ARR/3.0
Connection: Upgrade
X-Powered-By: ASP.NET
Date: Fri, 10 Jun 2016 21:16:16 GMT
EndTime: 17:16:16.148
ReceivedBytes: 0
SentBytes: 0
So now they are connected. This all looks good, the only noticeable difference being that the Sec-WebSocket-Key and Sec-WebSocket-Accept is changed in both directions by either IIS or the ARR proxy.
But... no WebSocket frames ever make it through the proxy! When Chrome receives positive feedback on its upgrade request, it sends its WebSocket message frame, and it is then sitting and waiting for messages from the server. The Node.js server sends its frames, and no error occurs, but they are never received by Chrome. The message that Chrome sent is never received by Node.js. It appears that ARR/IIS is dropping the WebSocket frames in both directions.
Notice how Chrome is telling the server that it supports the permessage-deflate extension, which is a WebSocket extension for per-message compression. The server is responding that it also supports permessage-deflate, so when they browser and server send their messages to each other, they use this compression extension. HOWEVER, the guy in the middle, ARR, apparently does NOT support this compression! By turning off support for permessage-deflate on the server, the actual WebSocket frames can now pass through the proxy flawlessly:
const wss = new WebSocketServer({ port: 3011, perMessageDeflate: false });
I think the issue is that ARR 3.0 does not support the Sec-Websocket-Extensions header, so it is allowing the header to simply pass through. But allowing this header to be negotiated between the client and the server is wrong, because ARR is not involved in the negotiation and has no way of telling the two parties that it does not support passing compressed messages. Hopefully someday, ARR will be able to properly handle extensions by negotiating between itself and the client, and then doing a separate negotiation between itself and the server. As it stands now, it simply has the client and server negotiating with each other, which results in this error.
As stated by #jowo, IIS8/8.5 don't seem to support Sec-Websocket-Extensions. That being said, the workaround I applied is to simply rewrite the server variable in question. First add HTTP_SEC_WEBSOCKET_EXTENSIONS to the allowed server variable list, then add it to your rule:
<serverVariables><set name="HTTP_SEC_WEBSOCKET_EXTENSIONS" value="" /></serverVariables>
That way, the destination won't receive the troublesome permessage-deflate :)
In Server Manager, make sure you enabled Web Socket Protocol which is available under Web Server (IIS) > Web Server > Application Development
The TLDR is to:
url redirect the ws and wss protocols correctly
disable the compression in the node server socket io, passing the option perMessageDeflate. disable compression as APR 3 In IIS Proxy does not support it
const io = require("socket.io")(server, {
transports: ["websocket", "polling"],
perMessageDeflate: false
});

Resources