Socket.io: How to secure 'io' cookie

Created on 11 Oct 2015  ·  23Comments  ·  Source: socketio/socket.io

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.

Most helpful comment

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.

All 23 comments

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

Best answer ever - thanks!

Closing as resolved - thanks

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

@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
});

@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.

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

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.

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?

@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.

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 });

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

@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?

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.

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?

@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, 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);
 // }

}

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 }

, { cookie: false }

It didn't work. =/

What version of socket.io are you using?

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.

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

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});

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

Was this page helpful?
0 / 5 - 0 ratings