什么是Sec WebSocket密钥



在第1.3节中"打开握手";在draft-ietf-hybi-thewebocketprotocol-17中,它对Sec-WebSocket-Key的描述如下:

为了证明握手已被接收,服务器必须获取两条信息,并将它们组合起来形成响应。第一条信息来自客户端握手中的|Sec WebSocket Key|头字段:

Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

对于该报头字段,服务器必须取该值(如报头字段中存在的值,例如base64编码的[RFC4648]版本减去任何前导和尾随空白),并将其与全局唯一标识符(GUID,[RFC4122])"连接;258EAFA5-E914-47DA-95CA-C5AB0DC85B11";字符串形式,不太可能被不理解WebSocket协议的网络端点使用。该级联的SHA-1散列(160位),base64编码(参见[RFC4648]的第4节),然后在服务器的握手中返回[FIPS.180-2 2002]

有一件事我无法理解:为什么不简单地返回代码101呢?如果Sec-WebSocket-Key的正确使用是为了安全,或者为了证明它们可以处理websocket请求,那么任何服务器都可以返回期望的密钥,如果他们愿意的话,并假装自己是websocket服务器。

根据RFC 6455 Websocket标准

第一部分:

.. the server has to prove to the client that it received the
client's WebSocket handshake, so that the server doesn't accept
connections that are not WebSocket connections.  This prevents an
attacker from tricking a WebSocket server by sending it carefully
crafted packets using XMLHttpRequest [XMLHttpRequest] or a form
submission.
...
For this header field, the server has to take the value (as present
in the header field, e.g., the base64-encoded [RFC4648] version minus
any leading and trailing whitespace) and concatenate this with the
Globally Unique Identifier (GUID, [RFC4122]) "258EAFA5-E914-47DA-
95CA-C5AB0DC85B11" in string form, which is unlikely to be used by
network endpoints that do not understand the WebSocket Protocol.

第二部分:

The |Sec-WebSocket-Key| header field is used in the WebSocket opening
handshake.  It is sent from the client to the server to provide part
of the information used by the server to prove that it received a
valid WebSocket opening handshake.  This helps ensure that the server
does not accept connections from non-WebSocket clients (e.g., HTTP
clients) that are being abused to send data to unsuspecting WebSocket
servers.

因此,由于GUID的值是在标准中指定的,所以不知道Websockets的服务器不太可能使用它。它不提供任何安全性(secure Websockets-ws://-do),它只是确保服务器理解Websockets协议。

实际上,正如您所提到的,如果您知道websocket(这就是要检查的内容),您可以通过发送正确的响应来假装是websocket服务器。但是,如果您的行为不正确(例如,正确形成框架),则会被视为违反协议。事实上,你可以编写一个不正确的websocket服务器,但它不会有太多用处。

另一个目的是防止客户端意外地请求websockets升级而不期望它(例如,手动添加相应的头,然后期望smth else)。浏览器中禁止使用setRequestHeader方法设置Sec WebSocket Key和其他相关标头。

主要用于缓存破坏。

想象一下,一个透明的反向代理服务器看着HTTP流量经过。如果它不理解WS,它可能会错误地缓存WS握手,并用一个无用的101回复下一个客户端。

使用高熵密钥并需要WS特有的基本挑战响应确保服务器实际上理解这是WS握手,并反过来"告诉"客户端服务器将确实在侦听端口;错误";。

我倾向于同意。

如果客户端忽略Sec-Webocket-Accept标头的值,则不会更改任何重要内容

为什么?因为服务器没有通过进行此计算来证明任何事情(除了它有进行计算的代码)。它几乎唯一排除的是一个服务器,它只是用一个固定的响应来回复。

标头的交换(例如,具有固定的"key"one_answers"accept"值)已经足以排除与至少不是WebSocket服务器的东西的任何意外连接;如果它正在尝试,那么要求它进行这种计算几乎不会阻碍它的成功。

RFC声称:

"..服务器必须向客户端证明它收到了客户端的WebSocket握手,这样服务器就不会接受不是WebSocket连接的连接。"

和:

"这有助于确保服务器不接受来自非WebSocket客户端的连接。"

这两种说法都没有任何意义。服务器永远不会拒绝连接,因为它是计算哈希的服务器,而不是检查哈希的服务器

如果神奇的GUID不是固定的,而是客户端和服务器之间的共享机密,那么这种交换是有意义的。在这种情况下,交换将允许服务器向客户端证明它拥有共享机密,而不会泄露。

RFC 6455规范显示了服务器需要响应客户端(浏览器)的(最少)4行。最困难的部分是确认您的Websocket服务器C代码正在进行正确的计算。这里有一个简短的PHP脚本(PHP很容易安装在所有操作系统上),它将正确计算要回复的密钥。将您从客户端(浏览器)获得的密钥硬编码到下面的第二行:

<?php
    $client_websocket_key = "IRhw449z7G0Mov9CahJ+Ow==";
    $concat = $client_websocket_key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    $ascii_sha1 = sha1( $concat );  // print this one for debugging, not used for real value.
    $sha1 = sha1( $concat, true );
    echo base64_encode( $sha1 );
?>

RFC不清楚的是,来自客户端的"Sec-Webocket-Key"标头在每个请求上都应该是随机的。这意味着来自代理的任何缓存结果都将包含无效的"Sec WebSocket Accept"回复标头,因此WebSocket连接将失败,而不是无意中读取缓存数据。

相关内容

  • 没有找到相关文章

最新更新