Sec-WebSocket-Accept值的Base64编码

前段时间,我开始尝试用Node.js来处理后端的WebSockets。 它工作正常,但现在当我返回协议已更新,我不能得到它正常工作了。

具体来说,问题是Sec-WebSocket-Accept头。 在计算时,我似乎做错了什么,尽pipe我不能真正理解那可能是什么。 据我所知,我遵循维基百科上的指示 。

这是我的代码:

 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进行进一步的实验,并从shell中的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= 

有时阅读手册实际上有帮助。

hash.digest([编码])

计算所有通过散列的数据的摘要。 编码可以是“hex”,“二进制”或“ 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); 

是时候感到愚蠢了。 (再次。)

使用这个http://pajhome.org.uk/crypt/md5/sha1.html和代&#x7801;

 b64pad = "="; var b64hash = b64_sha1(secWsKey + magicString); console.log(b64hash);