socketio / socket.io

Realtime application framework (Node.JS server)
https://socket.io
MIT License
60.97k stars 10.1k forks source link

How to secure 'io' cookie #2276

Closed dglozic closed 8 years ago

dglozic commented 8 years ago

I noticed that socket.io (engine.io to be precise) is setting a non-secure session cookie called 'io' on the URL it is invoked. What is the role of this cookie, is it necessary and if so, can it be secured? We force https:// for all locations where socket.io is running, and could easily set this cookie to secure but I cannot find where.

Nibbler999 commented 8 years ago

It's not used for anything; you can disable it by setting cookie: false in the server options.

dglozic commented 8 years ago

Best answer ever - thanks!

dglozic commented 8 years ago

Closing as resolved - thanks

wisniewski94 commented 7 years ago

@Nibbler999 Where are these options? Where exactly do I put this setting?

darrachequesne commented 7 years ago

@wisniewski94 the options are documented here: https://github.com/socketio/engine.io#methods-1

var io = require('socket.io')();
io.on('connection', function(client){});
io.listen(3000, {
  cookie: false
});
wisniewski94 commented 7 years ago

@darrachequesne thank you very much! Without your help it would be still unclear to me how to use them. It would be good idea to add example to README.md.

darrachequesne commented 7 years ago

On a broader note, that cookie may be removed, if it's not used anywhere.

tienlx93 commented 7 years ago

Hi @darrachequesne ,

Here is my current code.

var server = http.createServer(app);
var socket = require('socket.io');
var io = socket().listen(server,
    {
        cookie: false
    });

However, the server still send the cookie io. Is there a problem of cookie when integrate io with express server?

Thanks.

tienlx93 commented 7 years ago

One more thing, are there any method for sending the header Access-Control-Allow-Origin for web socket request (the 101 Switching Protocols response) I have set io.origins(config.origin) in init step, however, it only apply for XHR request.

The background is if there is a request that not setting correct Origin header is an vulnerable request, is this correct?

darrachequesne commented 7 years ago

@tienlx93 I'm not able to reproduce: https://github.com/darrachequesne/socket.io-fiddle/tree/issues-2276

The background is if there is a request that not setting correct Origin header is an vulnerable request, is this correct?

The Access-Control-Allow-Origin header only applies for cross-domain requests (MDN). If you set the allowed origins with io.origins(), it should be ok.

lkende commented 6 years ago

Thanks for the info. For reference, another way to set this cookie false when using express as the server:

var server = require('http').createServer(express());
var io = require('socket.io')(server, { path:"/some/path", cookie: false });
DaVincii commented 6 years ago

@darrachequesne In socket.io-2.0, is there a way to set this cookie secure and remove it from the query string.

jquinter commented 5 years ago

@darrachequesne In socket.io-2.0, is there a way to set this cookie secure and remove it from the query string.

can you please post how to do this in socket.io^2.0?

dae721 commented 4 years ago

Recently noticed a warning in Chrome console regarding this cookie: A cookie associated with a cross-site resource at (URL) was set without the SameSite attribute. A future release of Chrome will only deliver cookies with cross-site requests if they are set with SameSite=None and Secure.

In case it helps anyone who searches and ends up here, setting the option cookie: false as above seems to have solved the issue for me. I'm no longer getting the warning and the app is working fine without the cookie being set.

GuilhermeCouto commented 4 years ago

Recently noticed a warning in Chrome console regarding this cookie: A cookie associated with a cross-site resource at (URL) was set without the SameSite attribute. A future release of Chrome will only deliver cookies with cross-site requests if they are set with SameSite=None and Secure.

In case it helps anyone who searches and ends up here, setting the option cookie: false as above seems to have solved the issue for me. I'm no longer getting the warning and the app is working fine without the cookie being set.

It doesn't work for me.

My code:

http.listen(port, {cookie: false}, function(){
  console.log('listening on *:' + port);
});

What is wrong?

dae721 commented 4 years ago

@GuilhermeCouto, I think you need to set the {cookie: false} option when initializing the socket, not http.listen. The solution provided above that worked for me is the one that uses express:

var server = require('http').createServer(express());
var io = require('socket.io')(server, { path:"/some/path", cookie: false });

Hope this helps

GuilhermeCouto commented 4 years ago

@GuilhermeCouto, I think you need to set the {cookie: false} option when initializing the socket, not http.listen. The solution provided above that worked for me is the one that uses express:

var server = require('http').createServer(express());
var io = require('socket.io')(server, { path:"/some/path", cookie: false });

Hope this helps

Thank you Doug for the reply. Just more one question? What do I put in path? My system works like this: There is a local network that other pcs connect to the local server. The internal IP varies for each customer.

My Code:

var app = require("express")();
var http = require("http").Server(app);
var io = require("socket.io")(http);
var port = process.env.PORT || 3000;

// maps socket.id to user"s nickname
var nicknames = {};
// list of socket ids
var clients = [];
var namesUsed = [];

app.get("/", function(req, res){
  res.sendFile(__dirname + "/index.html");
});

io.on("connection", function(socket){  
    handleNewUser(socket);  
    handleTV(socket);
    //showActiveUsers(socket);
    handleClientDisconnections(socket);
    handleMessageBroadcasting(socket);
    handlePrivateMessaging(socket);
});

http.listen(port, function(){
  console.log("listening on *:" + port);
});

function handleTV(socket) {
    socket.on("flugo message", function(msg){
        console.log("flugo message"); 
       io.emit("flugo message", msg);
    });
}

function handleNewUser(socket){
  socket.on("user join", function(atendente) { 
  console.log("user join");   
  if (atendente) {      
        var ind = namesUsed.indexOf(atendente.nome);
        if (ind !== -1) {
          //ja tem alguem com esse nome, pode ser a mesma conexao da mesma pessoa
          clients[ind] = socket;
          nicknames[socket.id] = atendente;
        }else
        {
            ind = namesUsed.push(atendente.nome) - 1;
            clients[ind] = socket;
            nicknames[socket.id] = atendente;
        }

        //io.sockets.emit("new user", {id: ind, from: from});
        showActiveUsers(socket);
    }
  });
}

function handleMessageBroadcasting(socket){
  socket.on("message", function(msg,callback){
    console.log("message"); 
    if(nicknames[socket.id])
    {
        var from = nicknames[socket.id].nome;
        var user_id = nicknames[socket.id].id;
        var now = new Date();
        io.sockets.emit("message", {id: user_id, from: from, date: now.getTime(), msg: msg}); 
        callback("message");   
    }
  });
}

function handlePrivateMessaging(socket){
  socket.on("private message", function(data, callback){
    console.log("private message"); 
    if(nicknames[socket.id])
    {
        var from = nicknames[socket.id].nome;  
        var user_id = nicknames[socket.id].id;   
        var ind = namesUsed.indexOf(data.userToPM);
        if (ind !== -1) {
            var now = new Date();
            clients[ind].emit("private message", {id: user_id, from: from, date: now.getTime(), msg: data.msg}, function(data2, callback2){
                callback("private message");
            });         
        } 
    }   
  });
}

function handleClientDisconnections(socket){
  socket.on("disconnect", function(){
    console.log("disconnect"); 
    if(nicknames[socket.id])
    {
        var ind = namesUsed.indexOf(nicknames[socket.id].nome);
        var at = nicknames[socket.id];
        delete namesUsed[ind];
        delete clients[ind];
        delete nicknames[socket.id];
        io.sockets.emit("user disconnect", at);
    }
  });
}

function showActiveUsers(socket){
  var activeNames = [];
  var usersInRoom = io.sockets.sockets;
  console.log("names"); 
  //if(usersInRoom!===undefined){
    for (var index in usersInRoom){
        var userSocketId = usersInRoom[index].id;
        if (nicknames[userSocketId]){
          var name = nicknames[userSocketId].nome;
          activeNames.push({id: namesUsed.indexOf(name), from: name});
        }
      }
      io.sockets.emit("names", activeNames);
 // }

}
dae721 commented 4 years ago

That snippet was from Ikende's answer above so I'm not entirely sure what the path option is referring to, but I don't think you need to specify it. If it helps, here are the relevant snippets of my code (I'm using typescript):

import * as express from 'express';
import { createServer, Server } from 'http';
import * as socketIo from 'socket.io';

this.app = express();
this.server = createServer(this.app);
this.io = socketIo(this.server, { cookie: false });
this.server.listen(this.port, () => {
            this.log('Running server on port ' + this.port);
        });
this.io.on('connect', (socket: SocketIO.Socket) => { bunch of code here }
GuilhermeCouto commented 4 years ago

, { cookie: false }

It didn't work. =/

What version of socket.io are you using?

dae721 commented 4 years ago

2.2.0. My memory is kind of fuzzy, but I think I needed to exit Chrome and start a new instance and/or manually remove the cookie via Chrome Dev Tools on the Application page to verify the fix. Edit: I probably also had to kill and restart the server application.

Kugelschieber commented 4 years ago

Why does it even exist if it's not used?

georgerappel commented 4 years ago

For those using http and https servers, with the io.attach method, this worked for me:

io.attach(httpServer, {cookie: false});
io.attach(httpsServer, {cookie: false});
CoDanny commented 4 years ago

As opposed to what other people are saying here, this cookie is useful to provide stickiness in a system with multiple concurrent instances of a socket.io server as explained here in the Haproxy option: https://socket.io/docs/using-multiple-nodes.

However since there's no option to set sameSite on the cookie, we can't use it