Кодировка Base64 для значения Sec-WebSocket-Accept - PullRequest
6 голосов
/ 24 января 2012

Некоторое время назад я начал экспериментировать с WebSockets с Node.js, заботясь о бэкэнде. Он работал нормально, но теперь, когда я возвращаюсь, протокол был обновлен, и я больше не могу заставить его работать должным образом.

В частности, проблема в заголовке Sec-WebSocket-Accept. Я, кажется, делаю что-то не так при расчете, хотя я не могу понять, что это может быть. Насколько я могу судить, я следую инструкциям в Википедии до точки.

Вот мой код:

var magicString = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
var secWsKey = req.headers['sec-websocket-key'];
var hash = require('crypto')
             .createHash('SHA1')
             .update(secWsKey + magicString)
             .digest('hex');
var b64hash = new Buffer(hash).toString('base64');
var handshake = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" +
            "Upgrade: WebSocket\r\n" +
            "Connection: Upgrade\r\n" +
            "Sec-WebSocket-Accept: " + b64hash + "\r\n" +
            "\r\n";

socket.write(handshake);

Пример подключения:

// The incoming headers
{ upgrade: 'websocket',
  connection: 'Upgrade',
  host: 'localhost:8888',
  origin: 'http://localhost:8888',
  'sec-websocket-key': '4aRdFZG5uYrEUw8dsNLW6g==',
  'sec-websocket-version': '13' }

// The outgoing handshake
HTTP/1.1 101 Switching Protocols
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Accept: YTYwZWRlMjQ4NWFhNzJiYmRjZTQ5ODI4NjUwMWNjNjE1YTM0MzZkNg==

// Result: Error during WebSocket handshake: Sec-WebSocket-Accept mismatch

Посмотрев больше на это, я попытался воспроизвести вычисленный хэш в вики, и он потерпел неудачу.

var hash = require('crypto')
            .createHash('SHA1')
            .update('x3JJHMbDL1EzLkh9GBhXDw==258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
            .digest('hex');

// Result  : 1d29ab734b0c9585240069a6e4e3e91b61da1969
// Expected: 1d29ab734b0c9585240069a6e4e3e91b61da1969

var buf = new Buffer(hash).toString('base64');

// Result  : MWQyOWFiNzM0YjBjOTU4NTI0MDA2OWE2ZTRlM2U5MWI2MWRhMTk2OQ==
// Expected: HSmrc0sMlYUkAGmm5OPpG2HaGWk=

Как видите, хеш SHA1 верен, а кодировка base64 - нет. Глядя на этот ответ , кажется, я бы все сделал правильно. Я попробовал тот же процесс в PHP, и я получаю тот же результат, так что ясно, что я делаю это неправильно.

Я использую Node.js v0.6.8.

Подойдя ближе

Поэкспериментируя с PHP, который мне более знаком, и исходя из поведения printf в оболочке, я придумал следующий рабочий фрагмент:

$hash = sha1('x3JJHMbDL1EzLkh9GBhXDw==258EAFA5-E914-47DA-95CA-C5AB0DC85B11');
$hashdec = '';
for ($i = 0; $i < strlen($hash); $i += 2) { 
    $hashdec .= chr(hexdec(substr($hash, $i, 2))); 
};
echo base64_encode($hashdec);
// Result  : HSmrc0sMlYUkAGmm5OPpG2HaGWk=
// Expected: HSmrc0sMlYUkAGmm5OPpG2HaGWk=

Затем я попытался повторить это в JavaScript, но безрезультатно.

var magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
var key = "4aRdFZG5uYrEUw8dsNLW6g==";
var magic_key = magic + key;
var hash = require('crypto').createHash('sha1').update(magic_key).digest('hex');
var buf = new Buffer(hash.length / 2);

for (var i = 0; i < hash.length; i += 2) {
    var token = hash.substr(i, 2);
    var int = parseInt(token.toString(16), 16);
    var chr = String.fromCharCode(int);

    buf.write(chr);
}

console.log(buf.toString('base64'));

// Result  : w53dAAEAAADBIIAFAQAAAGGAtwA=
// Expected: HSmrc0sMlYUkAGmm5OPpG2HaGWk=

Ответы [ 2 ]

5 голосов
/ 25 января 2012

Иногда чтение руководства действительно помогает.

hash.digest ([кодировка])

Рассчитывает дайджест всех переданных данных для хеширования. Кодировка может быть «шестнадцатеричной», «двоичной» или « base64 ».

(Акцент мой.)

Итак, проблема была решена путем изменения кода на:

var magicString = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
var secWsKey = req.headers['sec-websocket-key'];
var hash = require('crypto')
             .createHash('SHA1')
             .update(secWsKey + magicString)
             .digest('base64'); // <- see that, silly.
var handshake = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" +
            "Upgrade: WebSocket\r\n" +
            "Connection: Upgrade\r\n" +
            "Sec-WebSocket-Accept: " + hash + "\r\n" +
            "\r\n";

socket.write(handshake);

'Это время чувствовать себя глупо. (Опять же.)

0 голосов
/ 17 февраля 2012

используйте это http://pajhome.org.uk/crypt/md5/sha1.html и код

b64pad = "=";
var b64hash = b64_sha1(secWsKey + magicString);
console.log(b64hash);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...