ERR_SSL_PROTOCOL_ERROR - Socket.io and Node.js - javascript

I’m working with the Node.js server and using the Socket.io to manage connections by Socket but I’m having a problem with the SSL certificate.
Lot of users can access the Node.js server normally, but others users doesn’t access and they receive this error:
When I set my server I have this SSL options:
var privateKey = fs.readFileSync('/root/cert/key.key', 'utf8').toString();
var certificate = fs.readFileSync('/root/cert/cert.crt', 'utf8').toString();
var ca = fs.readFileSync('/root/cert/ca.crt').toString();
var credentials = { key: privateKey, cert: certificate, ca: ca };
var app = express();
var httpsServer = https.createServer(credentials, app);
var io = require('socket.io')(httpsServer);
Somebody knows how to resolve this error? The problem is only some users receive this error.

Well, as far as I can see, you are missing a listening port for you https server.
var httpsServer = https.createServer(credentials, app).listen(<port>);

I had so much trouble with ERR_SSL_PROTOCOL_ERROR that I have to give you my solution
NodeJS server 16.15.0 with "socket.io": "2.4.1" (I assume it works with other NodeJS versions)
const path = require("path");
const fs = require("fs");
const io = require("socket.io")();
const folder = path.join(__dirname, "ssl");
const privateKey = fs.readFileSync(path.join(folder, "server_key.pem"), "utf8");
const certificate = fs.readFileSync(path.join(folder, "server_cert.pem"), "utf8");
const optSsl = {
key: privateKey,
cert: certificate,
ca: [certificate],
requestCert: false, // put true if you want a client certificate, tested and it works
rejectUnauthorized: false,
};
const server = require("https");
const webServer = server.createServer(optSsl);
webServer.listen(8025); // port number
io.listen(webServer);
io.on("connection", (client) => {
/*...*/
});
/*...*/
Angular 10.2.7 with "ngx-socket-io": "3.2.0" (I assume it works also with other Angular versions)
import { Socket, SocketIoConfig } from 'ngx-socket-io';
/*...*/
socket: Socket;
socketConfig: SocketIoConfig;
socketConfig = {
url: "https://myserver:8025",
options: {},
};
socket = new Socket(socketConfig);
socket.connect();

Looks like your apache2 is not properly configured.
Check if you have your config file enabled:
a2ensite default-ssl
And then restart the server.

Related

How to connect with elasticache using redis in nodejs

I have created a elasticache redis cluster in aws.
Now I have endpoint(url + port)
Url looks "myredis.abc.xyz.cache.amazonaws.com" and port 6379
Now I want to store Key:Value pair in it, like we store in native Redis (redis.set, redis.get)
How to write nodejs code for it, I don't know. I searched a lot but didn't find any right resource.
Anyone can help me in this?
I tried following code but didn't work
ElastiCacheClient,
AddTagsToResourceCommand,
} = require("#aws-sdk/client-elasticache");
const conf = {
host: "myredis.abc.xyz.cache.amazonaws.com",
port: 6379,
region: "us-east-1",
};
const client = new ElastiCacheClient(conf);
const param = { manoj: "kumawat" };
const command = new AddTagsToResourceCommand(param);
const data = await client.send(command);
console.log(data);

Node.js + Socket.io | Set custom headers on the server

I use Helmet with Express to set quite some security HTTP headers from the server side. This is nicely done, when rendering client pages on top of the node.js app, using:
var app = express();
app.use(helmet());
..
res.render("pages/index", data);
All the resources on the index page will have the Helmet headers. Unfortunately, socket.io does its own header management. So, anything that comes after /socket.io/ will have insecure/its own headers. For example here:
<https_path>/socket.io/socket.io.js
<https_path>/socket.io/?EIO=3&transport=polling&t=Lj4CFnj&sid=ILskOFWbHUaU6grTAAAA
Hence, I want to set custom headers for all socket.io items manually.
This is how I require socket.io (excerpt only):
/src/app.js
var express = require("express");
var sio = require("socket.io");
var app = express();
var io = require("./../lib/io.js").initialize(app.listen(REST_PORT, () => {
logger.info("Application ready on port " + REST_PORT + " . Environment: " + NODE_ENV);
}));
/lib/io.js
exports = module.exports = {};
var sio = require("socket.io");
exports.initialize = function(server) {
var options = {
cookie: false,
extraHeaders: {
"X-Custom-Header-For-My-Project": "Custom stuff",
}
};
io = sio(server, options);
io.on("connection", function(socket) {
// logic
)};
The "extraHeaders" option doesn´t work, I guess it could only with socket.io-client. I did large amount of googling around, but not luck on this.
Also looked around how to use socket.request (apparently it helps with headers, according to: here), but I couldn´t figure that out either.
Could you guys help?
extraHeaders options will work as below, as you need to remove "transports: ['polling']," in case you are using, and use below pattern. This worked for me, and was able to send custom headers.
package used :- "socket.io-client": "^2.2.0",
this.socket = io(environment.host, {
path: `/api/backend/socket.io`,
origins: '*:*',
// transports: ['polling'],
transportOptions: {
polling: {
extraHeaders: {
'authorization': token,
'user-id' : userId
}
}
}
})
Ref:- https://socket.io/docs/client-api/#With-extraHeaders

Is there a way to communicate with WebSocket over SSL from NativeScript app?

Currently I am writing a NS app that will communicate with a WebSocket over SSL. Here is server's code (server.js):
var fs = require('fs');
var cfg = {
port: 8082,
ssl_key: fs.readFileSync('keys/server.key'),
ssl_cert: fs.readFileSync('keys/server.crt'),
ca: fs.readFileSync('keys/ca.crt')
};
var httpServ = require('https');
var WebSocketServer = require('ws').Server;
var app = null;
// dummy request processing
var processRequest = function( req, res ) {
res.writeHead(200);
res.end("All glory to WebSockets!\n");
};
app = httpServ.createServer({
// providing server with SSL key/cert
key: cfg.ssl_key,
cert: cfg.ssl_cert,
ca: cfg.ssl.ca,
passphrase: '1234',
requestCert: true,
rejectUnauthorized: false,
}, processRequest ).listen( cfg.port );
var wss = new WebSocketServer( { server: app } );
wss.on('connection', function(ws) {
console.log("Connected!");
ws.on('message', function(message) {
console.log('received: %s', message);
});
ws.send('something');
});
Server is running well without problem. Below is the client code (wsclient.js):
const WebSocket = require('ws');
const ws = new WebSocket('wss://localhost:8082');
ws.on('open', function open() {
ws.send("dummy");
ws.on('error', function(evt) {
console.log("The socket had an error", evt.error);
});
});
When I ran the client by typing node wsclient.js, it throw the following error:
Error: unable to verify the first certificate
Obviously, the error was caused by not providing the certificate info to the request. But I have no idea how to get this done in my client code. Thanks a lot for any clues or suggestions.
Finally I found the answer:
const WebSocket = require('ws');
const ws = new WebSocket('wss://localhost:8082',{
key: fs.readFileSync('./keys/client.key'),
cert: fs.readFileSync('./keys/client.crt'),
ca: fs.readFileSync('./keys/ca.crt')
});
ws.on('open', function open() {
ws.send("dummy");
ws.on('error', function(evt) {
console.log("The socket had an error", evt.error);
});
});
Now it works!

Node.js error with SSL UNABLE_TO_VERIFY_LEAF_SIGNATURE

System: Windows 7
NodeJS version: 0.10.2
WS module: ws, last version
Error:
events.js:72
throw er; // Unhandled 'error' event
^
Error: UNABLE_TO_VERIFY_LEAF_SIGNATURE
at SecurePair. (tls.js:1283:32)
at SecurePair.EventEmitter.emit (events.js:92:17)
at SecurePair.maybeInitFinished (tls.js:896:10)
at CleartextStream.read [as _read] (tls.js:430:15)
at CleartextStream.Readable.read (_stream_readable.js:294:10)
at EncryptedStream.write [as _write] (tls.js:344:25)
at doWrite (_stream_writable.js:211:10)
at writeOrBuffer (_stream_writable.js:201:5)
at EncryptedStream.Writable.write (_stream_writable.js:172:11)
at write (_stream_readable.js:547:24)
Server:
(function(){
"use strict";
var fs = require('fs');
// you'll probably load configuration from config
var cfg = {
ssl: true,
port: 8080,
ssl_key: 'crt/server1.key',
ssl_cert: 'crt/server1.crt'
};
var httpServ = require('https')
var WebSocketServer = require('ws').Server;
var app = null;
// dummy request processing
var processRequest = function( req, res ) {
res.writeHead(200);
res.end("All glory to WebSockets!\n");
};
if ( cfg.ssl ) {
app = httpServ.createServer({
// providing server with SSL key/cert
key: fs.readFileSync( cfg.ssl_key ),
cert: fs.readFileSync( cfg.ssl_cert ),
//requestCert: true,
//rejectUnauthorized: false
}, processRequest ).listen( cfg.port );
} else {
app = httpServ.createServer( processRequest ).listen( cfg.port );
}
// passing or reference to web server so WS would knew port and SSL capabilities
var wss = new WebSocketServer( { server: app } );
wss.on( 'connection', function ( wsConnect ) {
wsConnect.on( 'message', function ( message ) {
console.log( message );
});
});
}());
Client:
var WebSocket = require('ws');
var ws = new WebSocket('wss://localhost:8080');
ws.on('open', function() {
ws.send('something');
});
The certificate confirmed.
Help> please!
I'm using a package called "superagent" and getting the same error. After trying several potential fixes, I came across this one that works for me 100% of the time:
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
There's no need to do any requires or whatever : just add this to your code before your network calls and you're good to go.
The SSL certificate used by the server in your example is probably not fully trusted by the WebSocket client so NodeJS is throwing an error in its network library on the client-side.
You need to set rejectUnauthorized to false (this is an option that most high-level network libraries will allow you to set via an option that gets passed to the lower level NodeJS networking library).
I skimmed the ws module source code and looks like you should try this:
var ws = new WebSocket('wss://localhost:8080', null, {rejectUnauthorized: false});
NOTE: rejectUnauthorized should only be false during testing/development. Production applications should always use rejectUnauthorized: true for full security.
If you do not want to disable your security. Add ca: [cert] option in http /socket client options.
Where cert is Certificate of server you are connecting to or CA of the server you are connecting to.
I've encountered a similar problem before, you may try to use
https.globalAgent.options.secureProtocol = 'SSLv3_method'
to set SSLv3 connection for https.
As per the nginx official website, they clearly mentioned certificate should be the combination of The server certificate and chained certificates.MoreInfo
Below solution is prefect and working fine for me in node js
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
Use a library to load the certificates (pem, crt, ...) from a given folder.
https://github.com/fujifish/syswide-cas
You can export the certificates from the browser and try:
const syswidecas = require('syswide-cas');
syswidecas.addCAs('./certs');

Socket.IO can't connect through https

I have a node.js app, that uses socket.IO. It works fine on http, but when trying to connect to the socket through https - nothing happens.
Here's some part of the code:
var fs = require('fs');
var ioHttp = require('socket.io').listen(8899, {
'flash policy port': -1
});
initSocket(ioHttp);
var ioHttps = require('socket.io').listen(8895, {
key: fs.readFileSync('/path/to/file/file.key'),
cert: fs.readFileSync('/path/to/file/file.crt'),
ca: [
fs.readFileSync('/path/to/file/sub.class1.server.ca.pem'),
fs.readFileSync('/path/to/file/ca.pem')
],
'flash policy port': -1
});
initSocket(ioHttps);
and the initSocket function:
function initSocket(io) {
io.enable('browser client minification');
io.enable('browser client etag');
io.enable('browser client gzip');
io.set('transports', [
'websocket',
'htmlfile',
'flashsocket',
'jsonp-polling'
]);
io.sockets.on('connection', function (client) {
//the connnection is handled here
});
}
The client connect like this:
var secureConnection = false;
var port = 8899;
if (window.location.protocol === 'https:') {
port = 8895;
secureConnection = true;
}
var socket = io.connect('domain.org', {port: port, secure: secureConnection});
As I said everything works fine on http, but connecting on https gives me "The connection was interrupted". What am I doing wrong?
You cannot initalize socket.io server like https server. You have to start a separate https server and then attach socket.io server to it.
var https = require('https'),
fs = require('fs');
var options = {
key: fs.readFileSync('ssl/server.key'),
cert: fs.readFileSync('ssl/server.crt'),
ca: fs.readFileSync('ssl/ca.crt')
};
var app = https.createServer(options);
io = require('socket.io').listen(app); //socket.io server listens to https connections
app.listen(8895, "0.0.0.0");

Categories

Resources