【问题标题】:WebSocket handshake hash is wrong after encoding编码后WebSocket握手哈希错误
【发布时间】:2019-05-09 13:34:15
【问题描述】:

我正在编写一个 TCP 套接字服务器应用程序来接受来自 Angular 应用程序的数据。在服务器应用程序中,我想向 web-socket 请求返回响应标头,但是在生成哈希的 base64 时,我得到的值很长(并且不正确),因此握手失败。

我正在使用System.NetEncoding 单元中的TNetCoding 类进行编码。一个例子可以在https://flixengineering.com/archives/270找到。

我得到了类似的东西:

YWRiYzRlYmJiMDkyZmM2MzNjMGJjMGZjNGY0YjQwOTllZjVhNWMxMw==

procedure TServerForm.SendHeader(key: string);
var
  hash, ret, encod: string;
const
  magic = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
begin
  hash := trim(key) + magic;
  ret := GenStrHashSHA1(hash);
  encod := TNetEncoding.Base64.Encode(ret);
  CliSocket.SendStr('HTTP/1.1 101 Switching Protocols' + #13#10 +
                   'Upgrade: websocket' + #13#10 +
                   'Connection: Upgrade' + #13#10 +
                   'Sec-WebSocket-Accept: ' + encod + #13#10 +  #13#10);
  Memo2.Lines.Add('Header was sent');
end;

/* Hash Function */
function TServerForm.GenStrHashSHA1(Str: String): String;
var
  HashSHA: THashSHA1;
begin
  HashSHA := THashSHA1.Create;
  HashSHA.GetHashString(Str);
  result := HashSHA.GetHashString(Str);
end;

例如:

传入请求:

GET / HTTP/1.1
Host: localhost:12345
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: http://localhost:4200
Sec-WebSocket-Version: 13
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Sec-WebSocket-Key: ky8at6EtBZLocDhJU7hMnw==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

哈希生成:

c289980eb715b3e19107152dc21f075c9f7bf539

Base64 字符串生成:

YzI4OTk4MGViNzE1YjNlMTkxMDcxNTJkYzIxZjA3NWM5ZjdiZjUzOQ==

更新:这是另一个例子:

收到 WebSocket 密钥:

Nk1L3oS2Q7LHdoGP2Uyn7Q==

调试时显示的十进制值:

生成的字符串:

F68FCEE74F044B57E9047395B975A31A6ABEBDD2

【问题讨论】:

  • 您能否提供一个minimal reproducible example,其中包含输入哈希、生成base64 的代码、生成的base64 以及您认为正确的base64。
  • 你为什么要给HashSHA.GetHashString(Str)打两次电话?
  • base64的长度是正确的。根据WebSocket protocol spec,SHA1 哈希的结果是 20 个字节,而您显示的 base64 解码为 20 个字节。所以这不是问题。如果您得到错误的哈希结果,那么您一开始就对错误的数据进行哈希处理。确保您散列的 key 与客户端的 Sec-WebSocket-Key 完全匹配(不要解码,不要修剪等)
  • 对哈希函数的额外调用是疏忽。
  • 得到的 base64 是 YWRiYzRlYmJiMDkyZmM2MzNjMGJjMGZjNGY0YjQwOTllZjVhNWMxMw== 我正在查看在 developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/… 找到的信息

标签: delphi delphi-xe2


【解决方案1】:

连接字符串的正确 SHA1 哈希

ky8at6EtBZLocDhJU7hMnw==258EAFA5-E914-47DA-95CA-C5AB0DC85B11

这是(通过多个在线 SHA1 哈希站点验证):

51D265858FE3CF00E77A63FBC2C2327D89579B07

不是这个,就像你展示的那样:

c289980eb715b3e19107152dc21f075c9f7bf539

因此,由于哈希错误,您的 WebSocket 握手失败。

另外,因为THashSHA1.GetHashString() 返回一个十六进制编码字符串,这就是你的base64编码,但你需要base64编码原始哈希字节,而不是这些字节的十六进制字符串表示。

试试这个:

procedure TServerForm.SendHeader(key: string);
var
  encod, ret: TBytes;
const
  magic = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
begin
  ret := THashSHA1.GetHashBytes(key + magic);
  encod := TNetEncoding.Base64.Encode(ret);
  CliSocket.SendStr('HTTP/1.1 101 Switching Protocols' + #13#10 +
                    'Upgrade: websocket' + #13#10 +
                    'Connection: Upgrade' + #13#10 +
                    'Sec-WebSocket-Accept: ' + TEncoding.ASCII.GetString(encod) + #13#10 +
                    #13#10);
  Memo2.Lines.Add('Header was sent');
end;

生成的base64应该是:

UdJlhY/jzwDnemP7wsIyfYlXmwc=

【讨论】:

  • 感谢您的帮助。我尝试了代码,发现 base64 值要短得多。然而,握手失败了。同样的消息:-“WebSocket 握手期间出错:net::ERR_INVALID_HTTP_RESPONSE”。所以我猜问题不仅仅是base64。
  • @Hugo 我没有看到您的 HTTP 响应有任何其他问题。在更改代码以处理字节而不是十六进制字符串后,您是否验证正在计算正确的哈希?我已经添加了你应该得到的 base64。另外,只是好奇,请求是通过 HTTPS 进来的吗?如果是这样,您的CliSocket 是否正确加密了响应?
  • 我相信这个请求来自一个 HTTP 请求。我在 Angular 应用程序中使用 websocket,如“ws://localhost:12345”。我不确定如何验证计算的哈希码。在调试过程中查看哈希,我看到:124、430、449、............、146。我该如何验证?
  • 为了直观地显示哈希,我使用了 TEncoding.ASCII.GetString(ret) 方法。但我得到了结果 - 'd>w ]/+GijZE7V8RB'。我该如何验证?
  • @Hugo 你在哪里看到这些十进制值?您无法从单个字节中获取 430 和 449 之类的值,您可以获得的最大值是 255。ASCII 字符 'd>w ... B' 是十进制 100 62 119 ... 66,十六进制 64 3E 77 42
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-20
  • 2021-11-13
  • 2014-04-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多