Nodejs Websocket server (using ws) won't run securely - javascript

I'm currently running a websocket server on a secure domain (with ssl) but for some reason I cannot get the server to actually use wss instead of ws.
The code below is how I create the Websocket server.
const httpsServer = https.createServer({
cert: fs.readFileSync(`/etc/letsencrypt/live/example.com/cert.pem`, 'utf8'),
key: fs.readFileSync(`/etc/letsencrypt/live/example.com/privkey.pem`, 'utf8'),
ca: fs.readFileSync(`/etc/letsencrypt/live/example.com/chain.pem`, 'utf8'),
})
const wss = new WebSocket.Server({
port: [port],
perMessageDeflate: false,
server: httpsServer,
})
wss.on('connection', (ws: ExtraWS, req) => {
ws.id = [id]
ws.send(`Connected to: ${req.socket.remoteAddress}:${req.socket.remotePort}`)
ws.on('message', msg => {
ws.send(`Recieved: '${msg}'`)
})
})
For whatever reason this socket is only available at ws://example.com:[port], instead of wss://example.com:[port]. If anyone knows what I'm doing wrong here please let me know.

I found the answer to this. The issue was that I was specifying the port in the Socket server instead of specifying it in the httpsServer.listen().
This is the amended code:
const httpsServer = https.createServer({
cert: fs.readFileSync(`/etc/letsencrypt/live/example.com/cert.pem`, 'utf8'),
key: fs.readFileSync(`/etc/letsencrypt/live/example.com/privkey.pem`, 'utf8'),
ca: fs.readFileSync(`/etc/letsencrypt/live/example.com/chain.pem`, 'utf8'),
})
httpsServer.listen([port])
const wss = new WebSocket.Server({
perMessageDeflate: false,
server: httpsServer,
})

Related

Getting error 503 on connection to secure web socket

When I'm making the connection using WSS protocol, I'm getting 503 on my back-end deployed on Heroku.
I'm using Netlify so they make me use only WSS protocol.
This is the error I'm getting:
WebSocketTester.3f92180b.js:1
WebSocket connection to 'wss://my-app-site/' failed: Error during WebSocket handshake: Unexpected response code: 503
this is my server side, i provided the cert and key:
const options = {
cert: readFileSync('./etc/ssl/certs/server.crt'),
key: readFileSync('./etc/ssl/private/key.pem')
};
const server = https.createServer(options, app);
const WebSocket = require('ws');
const wss = new WebSocket.Server({ server });
this is my client side:
if (!wsRef.current) {
wsRef.current = new WebSocket(`wss://my-site-url`);
wsRef.current.onopen = () => {
console.log('connection opened!');
}
wsRef.current.onmessage = ({ data }) => console.log(data);
wsRef.current.onclose = () => {
wsRef.current = null;
}
}
I would appreciate your help.

How to read headers from a websocket connection

i try to send an information on the header of a webSocket, and read it on the server on connection.
things like:
Client code is as simple as:
ws = await WebSocket.connect('ws://localhost.com:36485', headers: {
'codeName': 'Something',
},);
the server code:
var WebSocketServer = require('ws').Server
, wss = new WebSocketServer({ port: 36485 });
wss.on('connection', function connection(ws) {
console.log(ws.upgradeReq.headers);
ws.on('message', function incoming(message) {
console.log('received: %s', message);
});
});
the exception that i have is :
Type Error: Cannot read property 'headers' of undefined
If you're using this ws module on NPM, then way you get access to the headers like this (taken directly from the documentation):
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function(ws, req) {
console.log(req.headers);
});
thanks for your help, for some reason its not working with 'ws' but its working fine with 'webSoket'.
var webSocketServer = require('websocket').server;
var http = require('http');
wsServer.on('request', function(request){
console.log(request.httpRequest.headers['codename']);
}

Can't connect to local Node.js secure WebSocketServer

For testing a JavaScript / html5 application, I created a local WebSocketServer with node.js and ws package. I want to use secure websockets (wss) with SSL/TLS.
Key and certificate were create for testing purposes by OpenSSL locally (self signed certificate).
The client just tries to use the native WebSocket object to connect to the (local) https Server:
var ws = new Websocket('wss://localhost:8080');
The Problem is, no browser (Firefox, Chrome, Edge) can connect to the server and they all give me different error messages.
Firefox:
Firefox can not connect to the server at wss: // localhost: 8080 /.
Chrome:
ws_client.js:7 WebSocket connection to 'wss://localhost:8080/' failed:
Error in connection establishment: net::ERR_CERT_AUTHORITY_INVALID
Edge:
SCRIPT12017: SCRIPT12017: WebSocket Error: SECURITY_ERR, Cross zone
connection not allowed
I created the certificate and key in OpenSSL (light, newest version) like this:
openssl req -new -x509 -nodes -out server.crt -keyout server.key
(source)
I checked almost every question about this (and similar) topics, e.g. this question, but none of them could provide a solution.
Please do not mark this question as a duplicate, because all similar questions contain slightly different problems!
Server Code:
var fs = require('file-system');
var pkey = fs.readFileSync('server.key', 'utf8');
var crt = fs.readFileSync('server.crt', 'utf8');
var credentials = { key: pkey, cert: crt };
var https = require('https');
var httpsServer = https.createServer(credentials);
httpsServer.listen(8080);
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({
server: httpsServer
});
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
ws.send('reply from server : ' + message)
});
});
I tried another code as server, but same errors occur:
const WebSocketServer = require('ws').Server;
var fs = require('file-system');
var ws_cfg = {
ssl: true,
port: 8080,
ssl_key: 'server.key',
ssl_cert: 'server.crt'
};
var processRequest = function(req, res) {
console.log('Request received');
};
var httpServ = require('https');
var app = httpServ.createServer({
key: fs.readFileSync(ws_cfg.ssl_key, 'utf8', (error) => {
console.log('Error reading file');
}),
cert: fs.readFileSync(ws_cfg.ssl_cert, 'utf8', (error) => {
console.log('Error reading file');
})
}, processRequest).listen(ws_cfg.port, function(){
console.log('Server running');
});
var wss = new WebSocketServer( {server: app, port: 8080, host: 'localhost', domain: 'localhost'} );
wss.on('connection', function (ws) {
console.log('Connected to a client');
ws.on('message', function (message) {
console.log('MSG received: ' + message);
});
});
There's one more thing. Always, if I add a console.log(wss); to the server Code, the output looks something like this:
WebSocketServer {
domain: null,
...some more stuff...
...cert key etc....
host: null,
path: null,
port: null } }
host, domain and port is set to null. I tried everything to set it to localhost:8080, but nothing worked out. I think this could be the source of all Problems, but can't find a way. If anyone knows an answer to this question, I would highly appreciate it.
(Using the insecure 'ws' protocol ('ws://localhost:8080') in order to connect to local node.js http server works, but I want to test the app as realistic as possible and use a secure Connection.)
-- This is not an answer, just my workaround --
For anyone having the same problems, here is what I did:
Server Code should be:
const fs = require('fs');
const https = require('https');
const WebSocket = require('ws');
const server = new https.createServer({
cert: fs.readFileSync('localcert.cert'), //what ever you're files are called
key: fs.readFileSync('localkey.key')
});
const wss = new WebSocket.Server({ server }); // !
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('MSG received: %s', message);
});
ws.send('Hi to client');
});
server.listen(8080);
Only working in Google Chrome for now, can still not connect in Firefox.
enter chrome://flags/#allow-insecure-localhost in Google Chrome and enable.
Try to add the self-signed certificate or the generated CA to be trusted on the system that you are using.

Node.js, simple TLS client/server

I want create a simple secure client/server using TLS. I've follow instruction on the official doc. But I don't know how to create self-signed certificate with openssl (does not work with me).
Here code :
server.js
const tls = require('tls');
const fs = require('fs');
const options = {
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-cert.pem'),
// This is necessary only if using the client certificate authentication.
requestCert: true,
// This is necessary only if the client uses the self-signed certificate.
ca: [ fs.readFileSync('client-cert.pem') ]
};
const server = tls.createServer(options, (socket) => {
console.log('server connected',
socket.authorized ? 'authorized' : 'unauthorized');
socket.write('welcome!\n');
socket.setEncoding('utf8');
socket.pipe(socket);
});
server.listen(8000, () => {
console.log('server bound');
});
client.js :
const tls = require('tls');
const fs = require('fs');
const options = {
// Necessary only if using the client certificate authentication
key: fs.readFileSync('client-key.pem'),
cert: fs.readFileSync('client-cert.pem'),
// Necessary only if the server uses the self-signed certificate
ca: [ fs.readFileSync('server-cert.pem') ]
};
const socket = tls.connect(8000, options, () => {
console.log('client connected',
socket.authorized ? 'authorized' : 'unauthorized');
process.stdin.pipe(socket);
process.stdin.resume();
});
socket.setEncoding('utf8');
socket.on('data', (data) => {
console.log(data);
});
socket.on('end', () => {
server.close();
});
I don't know why use two different key-pair :
client-key.pem
client-cert.pem
and :
server-key.pem
server-cert.pem
Anyone can exmplain me ? For work in self-signed.
Sincerely,
Yoratheon
I solve my problem.
Solution here

Need help in setting up an HTTPS proxy using node.js, which picks up all the HTTPS requests from the browser window

I want to set up an HTTPS proxy server using node.js. It needs to pick up all the HTTPS requests from the browser window. I have a mac book and I have configured the proxy setting from the preferences for HTTPS. Below is the sample code for capturing any browser requests, is this code correct? I am generating the keys using the following commands.
openssl genrsa -out privatekey.pem 1024
openssl req -new -key privatekey.pem -out certrequest.csr
openssl x509 -req -in certrequest.csr -signkey privatekey.pem -out certificate.pem
var options = {
https: {
key: fs.readFileSync('privatekey.pem', 'utf8'),
cert: fs.readFileSync('certificate.pem', 'utf8')
},
target: {
https: true
}
};
https.createServer(options,function(request, response) {
console.log(request);
handleRequest(request, response);
}).listen(8877);
So the above code does not work, any suggestions how i can solve this problem, thanks in advance
You might want to check out https://github.com/nodejitsu/node-http-proxy which is an http proxy for node.js. With it, all you would have to do is
var httpProxy = require('http-proxy');
var options = {
https: {
key: fs.readFileSync('privatekey.pem', 'utf8'),
cert: fs.readFileSync('certificate.pem', 'utf8')
}
};
var port = SOME_PORT;
var host = 'SOME_HOST';
httpProxy.createServer(port, host, options).listen(8877);
Now that I know that you vary the host, I think you should rather build an http server that performs the proxying using request. Something like this (based on the request documentation):
var https = require('https'),
request = require('request');
var options = {
https: {
key: fs.readFileSync('privatekey.pem', 'utf8'),
cert: fs.readFileSync('certificate.pem', 'utf8')
},
target: {
https: true
}
};
https.createServer(options,function(req, resp) {
var otherhost = req.some_method_to_get_host;
console.log(req);
req.pipe(request(otherhost)).pipe(resp)
}).listen(8877);

Categories