HTTPS proxy with a self-signed certificate in Node.JS - node.js

I'm trying to create a HTTPS proxy server in Node.JS v0.10.24 using a self-signed certificate. Here's the code I'm using:
var https = require('https');
var server = https.createServer({
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
});
server.on('request', function(req, res) {
res.end('hello');
});
server.listen(8080);
This server correctly boots up and is accessible via https://localhost:8080. However, when I set it as a HTTPS proxy (on Mac OS X), the server emits connection events but never emits either request or error, thus causing the connection to hang indefinitely and eventually time out.

I encountered the same issue on my Macbook. The issue appears to be that the proxy server option in OSX is using the HTTP CONNECT method to tunnel HTTPS requests.
In short, this means that you need make your server a http.Server instance and handle the connect event, which will involve forwarding TCP socket traffic.
I know this reply is a bit late, but I wrote my own HTTP/S proxy server that you can look at for reference: https://github.com/robu3/purokishi. The specific section covering the connect method is here.

Related

Added SSL to client side server but still not performing handshake with backend server nodejs

I am trying to implement SSL on my nodejs project. Currently, my servers are split between a client side server running on localhost port 443 and a backend server running on localhost port 5000. I have already added a self-signed SSL certificate by openSSL to my client side server as shown below.
Now here's my issue. When I send a post request to login, from what I understand, a handshake is suppose to happen between the server and the client to make a secure connection. However, that's not the case. When I used Wireshark the intercept the packets, there is no handshake happening in the process.
I am currently not sure on how to proceed because I have limited knowledge on this kind of security topics. Do I need to sign a new key and cert and add it to my backend server? Or am I doing everything wrong? If so, can I get a source or guide on how to properly create one for a nodejs server?
you have many options here for securing your backend server :
first, you can use Nginx reverse proxy server and you can add ssl/tls logic to it. nginx will handle this stuff for you.
second, you can use [https][1] package directly and pass your SSL certificate and key to it :
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);
remember that the domain name your are trying to access must be set in your host ip.
[1]: https://nodejs.org/api/https.html

Nodejs SSL using CloudFlare not working over https

So the problem I'm having is that the client won't connect with the server.js when the server.js is using https.
if I go to "https://mydomainame.com" I get this error in the console of every other browser than brave browser
index.js:83 GET https://serverip:8081/socket.io/?EIO=3&transport=polling&t=NK0oCD6 net::ERR_CERT_AUTHORITY_INVALID
(The blacked out is the IP address of the server)
the weird thing is that in the brave browser the domain changes to "http://mydomainame.com" and the client then is connected to server.js
I'm using free Cloudflare with Full end to end encryption
server.js code:
var express = require('express'),
https = require('https');
var app = express();
var fs = require('fs');
var httpsOptions = {
key: fs.readFileSync('/var/www/ssl/sitename.com.key'),
cert: fs.readFileSync('/var/www/ssl/sitename.com.pem')};
var server = https.createServer(httpsOptions,app);
var io = require('socket.io').listen(server);
const port = 8081;
server.listen(port);
And client.js connection code:
socket = io.connect('https://serverip:8081', {secure: true});
I am using the same Origin Certificates for the server and for the nodejs code.
The server is using Apache2 with PHPMyAdmin and is configured to make the domain only work using https.
I read somewhere something Cloudflare not being able to use other ports than 443 and some other but I did not really understand it, And I can't get the server.js to work over port 443.
I'm thankful for any information or help I can get! :)
So I figured it out, big thanks to Eric Wong for pointing out the biggest problem that I was trying to connect to the server using its IP there for not going thru Cloudflare.
Then in this article Identifying network ports compatible with Cloudflare's proxy
you can see what ports Cloudflare allows connections on then, I changed my code to used the https port 8443.
socket = io.connect('https://domainname.com:8443',{secure: true});
then the only thing I had to do was to port forward the new port and everything worked fine!

Creating A HTTP proxy server with https support and use another proxy server to serve the response using nodejs

I need help creating a proxy server using node js to use with firefox.
the end goal is to create a proxy server that will tunnel the traffic through another proxy server (HTTP/SOCKS) and return the response back to firefox. like this
I wanna keep the original response received from the proxy server and also wanna support https websites as well.
Here is the code I came up with.
var http = require('http');
var request = require("request");
http.createServer(function(req, res){
const resu = request(req.url, {
// I wanna Fetch the proxy From database and use it here
proxy: "<Proxy URL>"
})
req.pipe(resu);
resu.pipe(res);
}).listen(8080);
But it has 2 problems.
It does not support https requests.
It also does not supports SOCKS 4/5 proxies.
EDIT: I tried to create a proxy server using this module. https://github.com/http-party/node-http-proxy
but the problem is we cannot specify any external proxy server to send connections through.
I have found a really super simple solution to the problem. We can just forward all packets as it is to the proxy server. and still can handle the server logic with ease.
var net = require('net');
const server = net.createServer()
server.on('connection', function(socket){
var laddr = socket.remoteAddress;
console.log(laddr)
var to = net.createConnection({
host: "<Proxy IP>",
port: <Proxy Port>
});
socket.pipe(to);
to.pipe(socket);
});
server.listen(3000, "0.0.0.0");
You have to use some middleware like http-proxy module.
Documentation here: https://www.npmjs.com/package/http-proxy
Install it using npm install node-http-proxy
This might help too: How to create a simple http proxy in node.js?

NodeJs SSL on Gandi Simple Hosting: listen EACCES

I am pretty desperate, the following problem is haunting me for weeks now:
I am encountering the "listen EACCES" error on my Gandi Simple Hosting instance, when i try to run my NodeJs instance on port 443.
Is there something i did wrong i didn't know about?
I must say that I'm very new to the whole hosting topic.
I am using NodeJs with Express, here's the relevant code:
var express = require('express')
, https = require('https');
var fs = require('fs');
var options = {
key: fs.readFileSync('./scrt/apiKey.key'),
cert: fs.readFileSync('./scrt/apiCrt.crt')
};
//....
app.set('port', process.env.PORT || 443);
//.....
https.createServer(options, app).listen(app.get('port'), function(){
});
Do you have any idea what i miss?
Maybe i have to change some configuration for the port 443?
I was just told by Gandi, that port 443 is the right port for SSL, so actually it should work...
Thank you very much in advance for your help!
Edit: No one here ever had the same problems with SSL on nodejs? :/
In Gandi Simple Hosting, SSL is done by a SSL offloader, you do not need to handle it by yourself.
The ssl offloader then redirects all incoming trafic (HTTP and HTTPS) on the instance's 8080 port.
To see if a request is secure, I bet you could look at the X-Forwarded-Proto header.
Ok I have had the answer from Gandi support team: all the traffic, SSL and not SSL is routed to the port 8080.
I still could not get it working since nodejs needs to handle one port for both traffic and it is not straightforward, see these posts
Is possible to run http and https server with same port no in node.js using express?
A node.js proxy that accepts HTTP and HTTPS traffic on the same port.
EDIT: #themouette is right, it works out of the box, no need to handle it in nodejs, but you need to activate the certificate on the domain level, but from your instance's admin page, which is not written in the docs.

Node.js+express proxy ssl

I'm trying to write a reverse proxy in node.js using express, and it works fine for http requests. The problem is that when requesting https it never responds, and the browser states that the proxy refused to connect.
Here is the working code for http requests:
var app = express(),
http=require('http');
app.configure(function(){ /* express stuff to log and use routes and the like */ });
http.createServer(app).listen(8000, function(){
console.log("Express server listening on port " + 8000);
});
app.all('*', proxy);
var request=require('request');
var proxy=function(req,resp){
var data={
url:req.url,
headers: {
'Connection': 'keep-alive'
}
}
var proxy=request(req.url);
proxy.pipe(resp);
}
Now, as for SSL, i am currently trying with:
var https=require('https'),
fs=require('fs');
https.createServer({
key: fs.readFileSync(__dirname+'/ssl/server.key', 'utf8'),
cert: fs.readFileSync(__dirname+'/ssl/server.crt', 'utf8')
},app).listen(8001, function(){
console.log("Express server listening on port " + 8001);
});
The proxy can be used from anywhere requiring 50.56.195.215:8000 for HTTP and 50.56.195.215:8001 for SSL. It has no security whasoever, so don't log in to anything important =D
I'm using a self signed SSL Certificate, and i guess it's kind of silly of me to try to do such a thing, but i don't have any ideas left :P
My suggestion is use the great existing library node-http-proxy from Nodejitsu. If you want to write your own, at least study their source code academically.
Some notes on your approach above:
You aren't handling HTTP methods other than GET (POST, PUT, DELETE, etc). These exist. You must handle them if you want your proxy to actually work. Every time you call request(req.url), request is making a GET request by default.
For HTTPS, you need to be able to handle HTTP Connects and also impersonate the destination server. You will need to have a Certificate for this.
You can try using this.
https://github.com/noeltimothy/noelsproxy
Copy the directory "magical" that contains a certificate as well as a key and then use noelsproxy. Remember to add the ca.pem to your trusted root store on your system.
If you are using windows, do this:
certutil -addstore -enterprise -f \"Root\" ./magical/ca.pem
Let me know if you have any issues. I'm willing to fix them immediately.

Resources