Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

socket.io cookie parse handshake error

When socket.io looks up a session, I get a handshake error because the id of the cookie does not match that from the database. I am using Express3, mongodb, connect-mongodb, and socket.io v0.9.10

For example, the result of the console.log(data.sessionID), from the socket.io code included, will print out:

s:eFFkUnQXWdTO7GBRDc11No/a.U6voj5QnxKs1skq766nO7/qJvPEJA73KaQM67qNEs/k

but when i look at the sessions collection on my database, I get the following _id:

"_id" : "eFFkUnQXWdTO7GBRDc11No/a",

As you can see this corresponds to the data.sessionID after the s: and before the period. I tried using two different cookie parsers. The code for the parser below is from the cookie module which is included in express 3. I am not sure if every cookie ID follows this pattern so I dont know if I should just parse the result again myself, or if there is something I am doing wrong.

exports.parseCookie = function(str) {
var obj = {}
var pairs = str.split(/[;,] */);
var encode = encodeURIComponent;
var decode = decodeURIComponent;

pairs.forEach(function(pair) {
    var eq_idx = pair.indexOf('=')
    var key = pair.substr(0, eq_idx).trim()
    var val = pair.substr(++eq_idx, pair.length).trim();

    // quoted values
    if ('"' == val[0]) {
        val = val.slice(1, -1);
    }

    // only assign once
    if (undefined == obj[key]) {
        obj[key] = decode(val);
    }
});

return obj;

};

The code below is giving me a handshake error, becuase the 'connect.sid' propert does not match the id property from the database.

io.set('authorization', function (data, accept) {

    if (data.headers.cookie) {
        data.cookie = utils.parseCookie(data.headers.cookie);
        data.sessionID = data.cookie['connect.sid'];
        // **************** //
        console.log(data.sessionID);
        // **************** //
        sessionStore.get(data.sessionID, function (err, session) {
            if (err || ! session) {
                accept('Error', false);
            } else {
                data.session = session;
                data.session.url = data.headers.referer;
                accept(null, true);
            }
        });
    } else {
       return accept('No cookie transmitted.', false);
    }
});
like image 540
Errol Fitzgerald Avatar asked Apr 03 '26 03:04

Errol Fitzgerald


2 Answers

I ran into the same issue and while your solution works, the parseCookie function you are using is from an older version of connect. The new code in connect now signs cookies, which is the extra characters after the period.

After some messing around in the guts of express and connect, I came up with the following code. While it depends on some a private API function of connect (utils.parseSignedCookies) it at least uses the same code to parse the cookie as was used to generate the cookie and should thus be a bit less sensitive to future changes in how the cookies are created and parsed.

/* cookie: the cookie string from the request headers
 * sid: the session 'key' used with express.session()
 * secret: the session 'secret' used with express.session()
 */
function parseSessionCookie(cookie, sid, secret) {
  var cookies = require('express/node_modules/cookie').parse(cookie)
    , parsed = require('express/node_modules/connect/lib/utils').parseSignedCookies(cookies, secret)
    ;
  return parsed[sid] || null;
}

socketIO.set('authorization', function(data, accept) {
  var sid = parseSessionCookie(data.headers.cookie, 'express.sid', 'secret');
  if (sid) {
    sessionStore.get(sid, function(err, session) {
      if (err || !session) {
        accept('Error', false);
      } else {
        data.session = session;
        accept(null, true);
      }
    });
  } else {
    return accept('No cookie transmitted.', false);
  }
}); 
like image 140
Paul Spencer Avatar answered Apr 04 '26 17:04

Paul Spencer


It seems the sessionStore keys are now the shorter uid(24)-only version and no longer the 'long' version stored in the cookie.

For the moment I fixed it by doing a simple split('.')[0] to retrieve the uid(24) part: data.sessionID = cookie['express.sid'].split('.')[0];

like image 36
Errol Fitzgerald Avatar answered Apr 04 '26 15:04

Errol Fitzgerald



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!