Sec-WebSocket-Accept值的Base64编码 [英] Base64 encoding for Sec-WebSocket-Accept value

查看:133
本文介绍了Sec-WebSocket-Accept值的Base64编码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

前一段时间,我开始尝试使用带有Node.js的WebSockets来处理后端.一切正常,但是现在当我返回协议时,协议已经更新,我无法使其正常工作.

具体地说,问题是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

对此进行了更多研究,我尝试在Wiki中复制计算出的哈希值,但操作失败.

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在shell中的行为派生而来,我想到了以下工作片段:

$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=

解决方案

有时阅读手册确实有帮助.

hash.digest([encoding])

计算要散列的所有传递数据的摘要.编码可以是十六进制",二进制"或" 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);

'该时间感到傻了. (再次)

A while ago, I started experimenting with WebSockets with Node.js taking care of the backend. It was working fine, but now when I return the protocol has been updated and I can't get it to work properly anymore.

Specifically, the problem is the Sec-WebSocket-Accept header. I seem to be doing something wrong when calculating it, although I can't really fathom what that might be. As far as I can tell, I'm following the instructions on Wikipedia to the dot.

Here's my code:

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

An example connection:

// 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

Looking more into this, I tried replicating the calculated hash in the wiki and it fails.

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=

As you can see, the SHA1 hash is correct, but the base64 encoding is not. Looking at this answer, it seems I would be doing it right. I tried the same process in PHP and I get the same result, so clearly I'm Doing It Wrong.

I'm running Node.js v0.6.8.

Getting closer

Experimenting further with PHP, which is more familiar to me, and deriving from the behaviour of printf in the shell, I came up with this working snippet:

$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=

I then tried to replicate this in JavaScript, but with no avail.

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=

解决方案

Sometimes reading the manual actually helps.

hash.digest([encoding])

Calculates the digest of all of the passed data to be hashed. The encoding can be 'hex', 'binary' or 'base64'.

(Emphasis mine.)

So the problem was solved by changing the code to:

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

'Tis time to feel silly. (Again.)

这篇关于Sec-WebSocket-Accept值的Base64编码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆