Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unique identifier for each client request to websocket server #859

Closed
altanai opened this issue Oct 12, 2016 · 19 comments
Closed

unique identifier for each client request to websocket server #859

altanai opened this issue Oct 12, 2016 · 19 comments

Comments

@altanai
Copy link

altanai commented Oct 12, 2016

Trying to find out if any attribute of the websocket server module can be used to extract a unique identifier for each unique client connecting to server .
So far tried following ,

  • ws._socket._handle.fd
  • ws.upgradeReq.url.substr(1)

however each of them yields unpredictable value ( ie works and doesnt work at times)

Ps : I am using websocket never without using express

@lpinca
Copy link
Member

lpinca commented Oct 12, 2016

You can add this info yourself every time a a new connection is established for example using node-uuid.

wss.on('connection', (ws) => {
  ws.id = uuid.v4();
});

or you can use a query parameter if you want to identify a client when it connects.

var ws = new WebSocket('ws://example.com/?token=abc123');

@lpinca lpinca closed this as completed Nov 8, 2016
@fvukovic
Copy link

@lpinca Can u explain it how to fetch that token parameter on the server side?
I tried we.token it's undefined?

@lpinca
Copy link
Member

lpinca commented Jan 31, 2018

@fvukovic

wss.on('connection', (ws, req) => {
  const { query: { token } } = url.parse(req.url, true);
  // ...
});

@sajadghawami
Copy link

sajadghawami commented Feb 8, 2018

@lpinca

wss.on('connection', (ws, req) => {
  const { query: { token } } = url.parse(req.url, true);
                                             ^
   TypeError: Cannot read property 'url' of undefined
});

@lpinca
Copy link
Member

lpinca commented Feb 8, 2018

@sajadghawami use ws@>=3 or replace req with ws.upgradeReq.

@sajadghawami
Copy link

@lpinca

Still getting same error:

wss.on('connection', (ws, req) => {
  const { query: { token } } = url.parse(ws.upgradeReq.url, true);
                                                ^
   TypeError: Cannot read property 'url' of undefined
});

Using "ws": "^4.0.0"

@lpinca
Copy link
Member

lpinca commented Feb 8, 2018

Reread my previous comment, upgrade or use upgradeReq, not both :). Since you are using ws@4 now the original snippet that uses req (#859 (comment)) is valid.

@sajadghawami
Copy link

sajadghawami commented Feb 8, 2018

Ahh i see :) ... but using the one you posted before didn't work either with ws@4...

you mean this:

wss.on('connection', (ws, req) => {
  const { query: { token } } = url.parse(req.url, true);
                                             ^
   TypeError: Cannot read property 'url' of undefined
});

@lpinca
Copy link
Member

lpinca commented Feb 8, 2018

Yes that one, on ws@>=3, req can't be undefined so I think there is something wrong with your setup.
Run npm ls ws to see the installed ws version.

@R0lin
Copy link

R0lin commented Feb 19, 2018

Use request header 'sec-websocket-key'

wss.on('connection', (ws, req) => {
      var id = req.headers['sec-websocket-key'];
      
      //do what ever you want...
});

@matinsoleil
Copy link

matinsoleil commented Sep 10, 2018

wss.on('connection', function connection(ws,req) {
  var url = req.url;
  url = url.substring(1);
  room = 1;
  ws['room']= url;
// do any
});

@rigwild
Copy link

rigwild commented May 7, 2019

@fvukovic

wss.on('connection', (ws, req) => {
  const { query: { token } } = url.parse(req.url, true);
  // ...
});

url.parse is deprecated since Node v11. You can use the URL constructor instead.
Otherwise, you can simply do this if you only have one query parameter.

wss.on('connection', (ws, req) => {
  ws.uuid = req.url.replace('/?uuid=', '')
});

@ncls-alien
Copy link

If I have a user with an account trying to connect to the websocket, how can I safely pass the user ID to the server and maybe even store the ID inside the client list?

@mehov
Copy link

mehov commented May 9, 2022

To whoever finds this on Google like I just did.

I have been looking into sec-websocket-key (also suggested above by @R0lin).

Keep in mind:

In addition to Upgrade headers, the client sends a Sec-WebSocket-Key header containing base64-encoded random bytes, and the server replies with a hash of the key in the Sec-WebSocket-Accept header. This is intended to prevent a caching proxy from re-sending a previous WebSocket conversation, and does not provide any authentication, privacy or integrity. (Source)

I'm not too sure if using 'Sec-WebSocket-Key' is a good ideas to identify a "session". This is because 'Sec-WebSocket-Key' does not accommodate scenario where the connection is dropped and the client is required to establish a new connection. A new 'Sec-WebSocket-Key' may be issued. The user would loose his/her session. (Source)

UPD I have just confirmed with a firewall test that once a connection is dropped and re-established, it gets a different sec-websocket-key, while being essentially the same session (at least from the browser point of view).

@e3dio
Copy link

e3dio commented May 9, 2022

If I have a user with an account trying to connect to the websocket, how can I safely pass the user ID to the server

Your app should be setting secure cookies after client authenticates, the cookies include session or user id. Cookies get sent with the websocket request in the header and is how you should be identifying the client

@netizen-ais
Copy link

Take into account that there're some ongoing efforts to deprecate cookies (also, cookie blocking browser extensions).
Other valid options are:

  • Send a custom http header (beware of proxy web servers configuration).
  • Or start by accepting the connection, and do a handshake for validation and identification.

@R0lin
Copy link

R0lin commented May 9, 2022

@mehov I don't know what are your needs but I've handled connections using onConnectionHandler event to handle
connectionId and I've also build a ConnectionManager to store and manage active connections. In my code, client will be added to active valid connections only after handshake and after receiving authentication token.

function onConnectionHandler(ws: ws, req: http.IncomingMessage) {
    let connectionId = req.headers['sec-websocket-key'] as string;
...
    ws.on("close", function () { onClose(connectionId ); });
}

If connection is dropped, close event will be fired and my onClose function will be called with connectionId in order to pass it to connectionManager calling my destroyConnection function.

Hope it helps

@e3dio
Copy link

e3dio commented May 9, 2022

Take into account that there're some ongoing efforts to deprecate cookies

There is no deprecation of 1st class Secure HttpOnly cookies. These are specially designed to hold sensitive data like session id's that can't be accessed by client-side javascript and should be your 1st choice for sending auth info

Use request header 'sec-websocket-key'

I don't know why people are giving that a thumbs up, you should not be using that as connection id, a bad client could send whatever value they want for that field. Your server should be assigning a generated connection id, incrementing an integer works fine

@lewis-walker
Copy link

Take into account that there're some ongoing efforts to deprecate cookies

There is no deprecation of 1st class Secure HttpOnly cookies. These are specially designed to hold sensitive data like session id's that can't be accessed by client-side javascript and should be your 1st choice for sending auth info

Use request header 'sec-websocket-key'

I don't know why people are giving that a thumbs up, you should not be using that as connection id, a bad client could send whatever value they want for that field. Your server should be assigning a generated connection id, incrementing an integer works fine

Incrementing an integer is a no-no too. It means it's super easy to find other valid uuids by just trying uuids that differ from your own by 1, 2, 3, -1, -2, -3....

That's why best practice is to generate a uuid using a cryptographic library

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests