Reputation: 48
I need a method how I can secure my WebSockets.
Something like onConnect->checkcredentials if(credentials===false){die()}
But with own credential data send to the server. How can I realize that without tokens or cookies? If not, is there any other solution to real-time communicate securely?
Upvotes: 0
Views: 2583
Reputation: 6219
I need a method how I can secure my WebSockets.
With this method, only clients that know the parameter and the secret will get through the handshake gateway (middleware)
[ EDIT: use the new socket.io 2.0
, it has fixed an issue regarding the query ]
@ client :
io('http://216.157.91.131:8080/', { query: "s=$€CR€T" });
@ server :
var theSecret = "S€CR€T";
io.use(function(socket, next) {
var handshakeSecret = socket.request._query['s'];
console.log("middleware:", handshakeSecret);
try{
if(handshakeSecret=theSecret){next();}else{socket.disconnect();}
}catch(e){socket.disconnect();} //prevent error - crash
});
In this case theSecret
is the same for all, could be a specific check in database.
You can also doom clients that connect to a disconnection (timer kick) if they dont supply correct credentials within the timeOut. Example :
const SOCKET_AUTH_TIMEOUT = 120000; //2 minutes in ms
io.on('connection', function(socket){
//.: ALL SOCKET CONNECTIONS :.
console.log("[+] (unauthorized) client connected : "+socket.id);
//begin doom countdown...
socket.doom = setTimeout(KickSocketClient.bind(null, socket.id), SOCKET_AUTH_TIMEOUT);
//warn this client : (example)
//@ client : 'You got '+TimeoutInMinutes+' minutes to authorize before being kicked.'
socket.emit('auth_required', SOCKET_AUTH_TIMEOUT);
//.: Handle Authorization :.
socket.on('auth',function(authRequest){
/* your logic to verify the incoming authRequest goes here, for example :*/
if(DATABASE[authRequest.user]){ //user exists in imaginary in-memory database
if(DATABASE[authRequest.user].password == authRequest.password){ //correct password, success!
socket.emit('authed', DATABASE[authRequest.user]); //maybe return user data
socket.authed = true; //set this socket client as authorized (useful for future requests)
//now clear the timeout of d00m! (prevent the disconnection, now the client is authed)
clearTimeout(socket.doom);
}else{socket.emit('error','credentials');}
}else{socket.emit('error','credentials');}
});
//.: Handle Disconnections :.
socket.on('disconnect', function(){
if(socket.authed){console.log("[+] client disconnected : "+socket.id);}
else{console.log("[+] (unauthorized) client disconnected : "+socket.id);}
});
//.: Only for Authorized Clients :.
socket.on('secret', function(){
if(socket.authed){
console.log("[o] client : "+socket.id+" requested the secret");
socket.emit('return','the secret to life'); //here you go!
}else{socket.disconnect();} // disconnect the unauthorized client
});
});
function KickSocketClient(sid){
if (io.sockets.connected[sid]) {
console.log("[kick] client ("+sid+") : unauthorized status for too long");
io.sockets.connected[sid].disconnect();
}else{ console.log("<!> : [kick] client ("+sid+") not found!"); }
}
If the client doesn't auth inside the time specified in SOCKET_AUTH_TIMEOUT
it will be disconnected.
I also included in the example, a small demo for a only-authorized clients (request while unauthed = disconnection)
You can also make them join specific private namespaces once authed, so that global broadcasts to all clients doesnt include the unauthed listeners.
Good luck, hope it helped.
NOTE :
is there any other solution to real-time communicate securely?
To answer this, you need to first think of the threats. There are many ways of being secure, for example, using socket.io over SSL.
The solutions I mentioned, are for avoiding unauthorized clients from staying online and accesing events/resources/etc...
Upvotes: 2