SNI proxy TLS session reuse over NodeJS - node.js

I'm setting up a SNI Proxy to be able to dynamically handle SSL connections on different domains. I'm using an HTTPS server with node-http-proxy (last version) over node.js v0.12 which supports SNI callback.
var sniOptions = {
SNIcallback : function(){
//dynamically fetch SSL certificate here
}
}
https.createServer(sniOptions, function (req, res) {
// node-http-proxy logic routes request here
});
All good so far but I haven't find yet a way to reuse the same TLS session. Everytime a request is received a brand new TLS session is created and I want to avoid this.
The only to resources strictly related to the topic are this issue on Github and this Paypal blog post.
Any suggestion about it?

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

How to proxy websocket connections to other websockets in NodeJS

I need to create a small authentication layer on top of a 3rd party web-socket based chat application. I have a simple API (get) that can validate api tokens from requests. What I want to do is essentially validate their token (which I know how to do) then proxy the websocket connection to the actual chat server.
I've been looking for solutions and this thread seems to give some pointers in the right direction however I can't get any of the solutions to work.
var http = require('http'),
WebSocket = require('faye-websocket'),
conf = require('./conf.json');
var server = http.createServer();
server.on('upgrade', function(request, socket, body) {
console.log('upgrade fired');
var frontend = new WebSocket(request, socket, body),
backend = new WebSocket.Client('ws://echo.websocket.org');
frontend.pipe(backend).pipe(frontend);
});
server.on('connection', function(socket) {
console.log('connection')
backend = new WebSocket.Client('ws://echo.websocket.org');
console.log(backend);
socket.pipe(backend).pipe(socket);
})
server.listen(conf.port);
console.log('Listening on '+port.conf);
The connection event is fired, however the upgrade event which is supposed to be fired on a ws connection never is.
The goal is to first authenticate a api key to an external server, then open a proxy to the chat websocket all through a request to this node server via a websocket connection. I'll most likely pass the api key as a get parameter for simplicity. I also looked at this package and attempted using it however it didn't work as well.
The issue ended up being with nginx. I forgot I was proxying requests through the reverse proxy and by default nginx does not support the ws:// connection so it drops it.

How can I know that a HTTPS endpoint receiving a TLS request from my node.js is using a specified SSL certificate?

I have an endpoint (in any language, let's say Python) that exposes some service as HTTPS using a certificate issued by any widely known and trusted CA, that is
probably included in virtually any browser in the world.
The easiest part is that I can issue TLS requests against this endpoint using Node.js with no further problems.
For security reasons, I would like to check that every time my Node.js issues a TLS request against this HTTPS endpoint, I want to make sure that the certificate being used, is the certificate that I trust, and the one that was requested by my company.
What is the best way to accomplish that?
It sounds like the answer at How to get SSL certificate information using node.js? would be suitable for your needs.
You can use the following code to get your endpoint's certificate then check its fingerprint or hash against what you expect.
var https = require('https');
var options = {
host: 'google.com',
port: 443,
method: 'GET'
};
var req = https.request(options, function(res) {
console.log(res.connection.getPeerCertificate());
});
req.end();

Yeoman generator-angular-fullstack enabling ssl

Trying to be able to run a SSL server using the generator-angular-fullstack https://github.com/DaftMonk/generator-angular-fullstack.
However when I look at all the examples for enabling SSL, when I comb through the code it doesn't seem to initialize the server the same way as the NodeJS documentation explains to:
var options = {
key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};
// Create a service (the app object is just a callback).
var app = express();
// Create an HTTP service.
http.createServer(app).listen(80);
// Create an HTTPS service identical to the HTTP service.
https.createServer(options, app).listen(443);
Has anyone had any success in doing it? Outside of that this generator seems to be incredible and easy to use.
Yes, the code above is how you run your app on 443, using the key and cert you have specified above. This should allow you to communicate with your app over HTTPS, assuming you have those keys (and of course you'll get warnings in the browser if they're self signed).
But yes, that works, and is how it's done. I've found that most people like to keep the Node app running on HTTP and instead use a web server (such as nginx) to deal with SSL. The communication from the web server to the Node app is then over HTTP. This helps keep the Node app easy to run in a development/test environment, and then in production you have the security of SSL.

Securing Socket.io

I am using a Node.js based https server that authenticates using HTTP Basic (which is fine as the data are sent over the SSL encrypted connection).
Now I want to provide a Socket.io connection which should be
encrypted and
for authenticated users only.
The question is how to do this. I already found out that I need to specify { secure: true } in the client JavaScript code when connecting to the socket, but how do I force on the server-side that socket connections can only be run over SSL, and that it works only for authenticated users?
I guess that the SSL thing is the easy part, as the Socket.io server is bound to the https server only, so it should run using SSL only, and there should be no possibility to run it over an (additionally) running http server, right?
Regarding the other thing I have not the slightest idea of how to ensure that socket connections can only be established once the user successfully authenticated using HTTP Basic.
Any ideas?
Edit: Of course OP is right in their other answer; what's more, with socket.io >1.0 you might use socket.io-express-session.
Original answer:
Socket.io supports authorization via the io.set('authorization', callback) mechanism. See the relevant documentation: Authorizing. Here's a simple example (this authenticates using a cookie-based session, and a connect/express session store -- if you need something else, you just implement another 'authorization' handler):
var utils = require('connect').utils;
// Set up a session store of some kind
var sessionId = 'some id';
var sessionStore = new MemoryStore();
// Make express app use the session store
app.use(express.session({store: sessionStore, key: sessionId});
io.configure(function () {
io.set('authorization', function (handshakeData, callback) {
var cookie = utils.parseCookie(handshakeData.headers.cookie);
if(!(sessionId in cookie)) {
return callback(null, false);
}
sessionStore.get(cookie[sessionId], function (err, session) {
if(err) {
return callback(err);
}
if(!('user' in session)) {
return callback(null, false);
}
// This is an authenticated user!
// Store the session on handshakeData, it will be available in connection handler
handshakeData.session = session;
callback(null, true);
});
});
});
Although the answer by Linus is basically right, I now solved it in a more easy way using the session.socket.io - which basically does the same thing, but with way less custom-code to write.
Setting the socket to be secured is done by:
setting the secure flag - as you wrote ({secure: true})
OR by using https protocol when creating the server (instead of http) - which will set the secure flag to be true automatically
Good lib that simplify the authentication process is: https://github.com/auth0/socketio-jwt

Resources