I have this code here -
const wss = new SocketServer({ express() });
wss.on('connection', ws => {
console.log('Client connected');
ws.on('message', msg => {
console.log('received: %s', msg);
});
ws.on('close', () => console.log('Client disconnected'));
});
Now there are some problems, A D-Dos attack can crash my server.
Is there a way to check a token or something before allowing a stranger to connect to the websocket? Also the socket will be on another domain so cookies won't work.
Or is there a way to disconnect a user if he has not sent the authentication token after connecting.
If it were running and allowing everyone to connect indefinitely, then that's a security risk. Server can be brought down easily.
With Socket.io possible a setup like you need, see Authenticating socket io connections
Otherwise you must implement it by your own, but you should follow some standards. The first ugly-hand-made solution that i can think is something like:
wss.on('connection', ws => {
console.log('Client connected');
isAuthenticated = false
ws.on('message', msg => {
if (!isAuthenticated ) {
// check if message is a token
// else comunicates back the error
}
console.log('received: %s', msg);
});
ws.on('close', () => console.log('Client disconnected'));
});
For the DDos attack, if they have a token they can spam infinite requests: same thing, you should count the incoming massage rate by your own and implementing something like a Throttling policy.
Related
I am on a websocket (socket.io) and I want to be able to force disconnect on a given user. I use this on my server file:
// kickout
socket.on('kickout', (sckid) => { //sckid is the socket.id of the kicked-out user
io.to(sckid).emit('kicked');
});
});
// kicked out
socket.on('kicked', () => {
socket.disconnect();
});
Then I do socket.emit('kickout', 'someusersocketid'); on my frontend but it won't work for some reasons. Seems like the server listens to "kickout" alright but so to "kicked". Why is that?
Try this one:
var clients = {}
sockets.on('connection', function(socket) {
clients[socket.id] = socket;
socket.on('disconnect', function() {
delete clients[socket.id];
});
});
I am using ssh2 and socket.io to enable a real-time ssh connection to a remote server for users of my Meteor 1.8.1 app. The app runs on Ubuntu under Nginx and Phusion Passenger. Here is what the app needs to do:
Each authorised user already has an account on the remote server.
A user will start a session by entering their credentials and clicking a "connect" button in the app.
The user can browse directory listings within their home directory on the remote server.
No user should have access to another user's ssh session.
Their ssh session should be removed from the server when the user clicks a "disconnect" button.
I have the ssh connection working but I can't figure out how to destroy the ssh connection at the end of the user's session. Each time they press disconnect" then "connect", another ssh session is started and the old ssh session is still operational, so each ssh command that is sent is executed multiple times and multiple responses are sent to the browser.
I'm also concerned that the connection isn't secure; in development I'm creating the server with require('http').createServer();. In production, on my Ubuntu server with SSL configured, is it enough to use require('https').createServer(); or is there other configuration required, e.g. of Nginx? Socket.io falls back to older technologies when websocket isn't available; how is that secured?
Main question: why am I seeing duplicate SSH sessions every time the user disconnects and then connects?
Secondary question: where can I find up to date instructions on how to secure socket.io? Or should I give up on socket.io and use WebSocket?
I have read a lot of articles and stack overflow posts, but I'm finding this very confusing and most of the material is out of date. For example socketio-auth is not maintained. I can find almost nothing in the Socket.io documentation on authentication or authorization - there is a handshake entry but it's not clear to me from this whether it's the function I need or how to use it.
Here's my code.
Server
io.on('connection', (socket) => {
console.log('socket id', socket.id); // this shows a new id after disconnect / reconnect
const conn = new SSHClient();
socket.on('disconnect', () => {
console.log('disconnect on server');
conn.end();
});
conn.on('ready', () => {
socket.emit('message', '*** SSH CONNECTION ESTABLISHED ***');
socket.emit('ready', 'ready');
conn.shell((err, stream) => {
stream.write('stty -echo \n'); // don't echo our own command back, or the user's password...
if (err) {
return socket.emit('message', `*** SSH SHELL ERROR: ' ${err.message} ***`);
}
socket.on('path', (path) => {
// path is a request for a directory listing
if (typeof path === 'string') {
const bashCommand = `ls -l ${path} --time-style=full-iso`;
console.log('*** WRITE'); // if you disconnect and reconnect this runs twice. Disconnect and reconnect again, it runs 3 times.
console.log('socket id again', socket.id); // this shows the same new socket id each time
stream.write(`${bashCommand} \n`);
}
});
stream.on('data', (d) => {
socket.emit('data', response); // tell the browser!
}).on('close', () => {
conn.end();
});
});
}).on('close', () => {
socket.emit('message', '*** SSH CONNECTION CLOSED ***');
}).on('error', (err) => {
socket.emit('message', `*** SSH CONNECTION ERROR: ${err.message} ***`);
}).connect({
'host': hosturl,
'username': ausername,
'agent': anagent, // just for dev I'm using public / private key from my local machine but this will be replaced with the user's entered credentials
});
}).on('disconnect', () => {
console.log('user disconnected');
});
server.listen(8080);
Client:
const io = require('socket.io-client');
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {};
const myEmitter = new MyEmitter();
const PORT = 8080;
let socket;
myEmitter.on('connectClicked', () => {
if (socket) {
this.connected.set(socket.connected);
}
if (this.connected.get() === false) {
socket = io(`http://localhost:${PORT}`);
socket.on('connect', () => {
this.connected.set(true);
socket.on('ready', () => {
console.log('ready');
});
// Backend -> Browser
socket.on('message', (data) => {
console.log('socket on message', data);
});
// Backend -> Browser
socket.on('data', (data) => {
console.log('got data', data);
this.parseResponse(data); // client function to handle data, not shown here
});
// Browser -> Backend
myEmitter.on('selectDirectory', () => {
console.log('*** SELECT DIRECTORY');
socket.emit('path', pathArray.join('/')); // path array is set in client code, it is a simple array of directory names
});
socket.on('disconnect', () => {
console.log('\r\n*** Disconnected from backend***\r\n');
this.connected.set(false);
});
});
}
myEmitter.on('disconnectClicked', () => {
socket.disconnect();
});
});
The answer to keeping the ssh connections separate is to maintain a list of current ssh connections and rework the code so that received ssh data is sent only to the browser that corresponds to the incoming message.
I've also given up on socket.io because I can't be confident about security. I'm now using Meteor's inbuilt DDP messaging system via the Meteor Direct Stream Access package. I think this avoids opening up any new points of access to my web server.
Scenario is i have a server where socket(1) runs i have one more server where socket(2) client connects to socket(1)
I have one browser socket which connects to socket(1)
Idea is to do request from browser and bring data from socket(2) server
Not sure how to difference between socket clients as all the sockets are similar to socket(1)
Ideally there will be multiple browser sockets and multiple socket(2) clients
Browser sockets can make request to any of the socket(2) clients
How to implement it using nodejs socket.io
Server
socket.on('action', (action) => {
if(action.type === 'server/hello'){
io.sockets.emit('broadcast',{ description: clients + ' clients connected!'});
console.log('Got hello data!', action.data);
}
});
Browser client
var socket = io.connect('localhost:3000', {reconnect: true});
socket.on('connect', function(data) {
socket.emit('joined', 'Hello World from client this is client plxx');
});
socket.on('response2', function(data) {
console.log("got it ", data);
$('#messages').append($('<li>').text(JSON.stringify(data)));
});
Server client
var io = require('socket.io-client');
var socket = io.connect('http://localhost:3000', {reconnect: true});
socket.on('broadcast', function (t) {
socket.emit("data", {data: 32})
console.log('broadcast! my host is est');
});
i should be able to communicate between socket clients
What I understood from your question is: you need to differentiate between sockets from different clients.
To solve that I would suggest simply emitting the socket source from the client on connect.
And on the server split the sockets into two lists.
Example:
Server
const BROWSER_CLIENTS = {};
const SERVER_CLIENTS = {};
io.on("connection", socket => {
socket.on("source", payload => {
if (payload == "browser")
BROWSER_CLIENTS[socket.id] = socket;
else if (payload == "server")
SERVER_CLIENTS[socket.id] = socket;
});
socket.on("disconnect", () => {
delete BROWSER_CLIENTS[socket.id];
delete SERVER_CLIENTS[socket.id];
});
});
Browser Client
socket.on("connect", () => {
socket.emit("source", "browser");
});
Server Client
socket.on("connect", () => {
socket.emit("source", "server");
});
Now when you receive an event you can detect from which source it originated. And if you need to send to all sockets of one type of clients you can simply do this:
Server
for (let i in BROWSER_CLIENTS)
BROWSER_CLIENTS[i].emit("Hello Browsers")
for (let i in SERVER_CLIENTS)
SERVER_CLIENTS[i].emit("Hello Servers")
EDIT: I found this link and thought you could make use of it. Socket.io Rooms
I have set up sockets on my client and server, but I can't seem to get my data to come into my client. It seems they are connecting properly, I just can't get any data to come through. There are no error messages either.
Here is my server code:
io.on('connection', function (socket) {
console.log('a user connected');
socket.on('custom-message', function () {
console.log("Hitting messages socket");
Message.find(function(err, messages){
if(err){
socket.emit('custom-message', err)
} else {
socket.emit('custom-message', messages);
}
})
});
});
Here is the function in the client that connects to the socket:
loadMessagesFromServer: function(){
console.log("About to load messages")
socket.on('custom-message', function(msg){
console.log("connected in client", msg)
});
},
Like I said it is a pretty simple example, I just can't seem to get the data in loadMessagesFromServer .. And there are no erros, the only way I have been debugging is trying different things..
You are listening on the event messages. So you need to emit the same event not socket.emit('messages: err', err). Try with socket.emit("messages", error). Moreover, in your server-side code, you need first to receive a message event and only then your socket will emit the messages. Remove the socket.on(custom-messages). Why do you need it?
Server-side code
io.on('connection', function (socket) {
/* Here a client connection is established. The on("connection")
* event will be triggered as many times as`io.connect("the-uri")`
* is triggered (and succeeded) in the client`
*/
// Listening for the post event
socket.on("post", function(messages){
console.log("client posted data:", messages)
// Find messages and emit result
Message.find(function(err, messages){
if(err){
socket.emit('error', err)
} else {
socket.emit("message", messages);
}
});
});
});
Client-side code
registerOnMessageFromServerListener: function(){
socket.on("message", function(msg){
console.log("received message:", msg);
});
registerOnErrorFromServerListener: function(){
socket.on("error", function(error){
console.log("an error occured:", error);
});
registerOnMessageFromServerListener();
registerOnErrorFromServerListener();
socket.emit("post", "a-message");
Also make sure that you call the loadMessagesFromServer before you establish the socket connection
I've been testing the functionality of keepalive in Node.js TCP sockets. It seems that I'm missing something here!
Here is my server code:
var net = require('net');
function accept(socket) {
socket.setKeepAlive(false);
socket.on('data', function(data) {
console.log("DATA");
console.log(data);
});
socket.on('error', function (e) {
console.log("ERROR");
console.log(e);
});
socket.on('close', function () {
console.log("CLOSE");
});
socket.on('end', function () {
console.log("END");
});
socket.write("Hi");
}
var server = net.createServer(accept);
server.listen(8011);
And it is my client code:
var net = require('net');
var socket = new net.Socket();
socket.setKeepAlive(false);
socket.on('data', function(data) {
console.log("DATA");
socket.write(data);
});
socket.on('error', function (e) {
console.log("ERROR");
console.log(e);
});
socket.on('close', function () {
console.log("CLOSE");
});
socket.on('end', function () {
console.log("END");
});
socket.connect(8011, '127.0.0.1');
Why does the server (or the client) not close the connection even if no data has been sent or received for a long time (120 sec)?
I'm using Node.js version 0.10.5!
Because keep-alive works at a lower level. It sends a check packet without any data payload and if there's no answer, then the connection is considered broken.
Try doing the same, but unplug your Ethernet cable from one of the machines.
Edit 0:
Sorry, misread your code a bit.
TCP keep-alive feature is often called "dead peer detection". Read about its mechanics, for example, here. With keep-alive disabled there's nothing in TCP itself that would force the connection to be closed after any inactivity timeout. It's intermediate devices like NAT-ing routers that may expire state and break your connection, not the communicating ends themselves.