Sec WebSocket密钥用于什么?

Sec WebSocket密钥用于什么?,websocket,Websocket,在的第1.3节“开放式握手”中,它描述了秒WebSocket键,如下所示: 为了证明收到了握手,服务器必须获取两条信息并将它们组合起来形成响应。第一条信息来自客户端握手中的| Sec WebSocket Key | header字段: Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== 对于此标头字段,服务器必须获取值(如标头字段中的值,例如base64编码的[RFC4648]版本减去任何前导和尾随空格),并将其与字符串形式的全局唯一标识符(GUID,[RF

在的第1.3节“开放式握手”中,它描述了
秒WebSocket键
,如下所示:

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

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密钥是为了安全,或者为了证明它们可以处理WebSocket请求,那么任何服务器都可以在需要时返回预期的密钥,并假装它们是WebSocket服务器。

根据RFC 6455 WebSocket标准

:

:

因此,由于GUID的值是在标准中指定的,所以不知道WebSocket的服务器不太可能使用它(可能,以很小的概率)。它不提供任何安全性(securewebsockets-wss://-does),它只是确保服务器理解websockets协议

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

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

我倾向于同意

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

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

交换标头(例如,使用固定的“key”和“accept”值)已经足以排除与至少不尝试成为WebSocket服务器的内容的任何意外连接;如果它正在尝试,要求它进行这种计算几乎不会阻碍它的成功

RFC声称:

“。服务器必须向客户端证明它已收到 客户端的WebSocket握手,因此服务器不接受 不是WebSocket连接的连接。“

以及:

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

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


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

主要用于破坏缓存

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


使用nonce(密钥)并需要特定于WS的基本质询响应,可以确保服务器真正理解这是WS握手,并反过来告诉客户机服务器确实正在侦听端口。缓存反向代理永远不会“错误地”实现该散列逻辑。

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

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

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

服务器说:未定义的索引秒WebSocket键。 当我通过手机访问网站时。从同一台pc(本地主机)不存在此类问题解决方案是什么:

function doHandshake($received_header,$client_socket_resource, $host_name, $port) {
        $headers = array();
        $lines = preg_split("/\r\n/", $received_header);
        foreach($lines as $line)
        {
            $line = chop($line);
            if(preg_match('/\A(\S+): (.*)\z/', $line, $matches))
            {
                $headers[$matches[1]] = $matches[2];
            }
        }

        $secKey = $headers['Sec-WebSocket-Key'];
        $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
        $buffer  = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
        "Upgrade: websocket\r\n" .
        "Connection: Upgrade\r\n" .
        "WebSocket-Origin: $host_name\r\n" .
        "WebSocket-Location: ws://$host_name:$port/demo/shout.php\r\n".
        "Sec-WebSocket-Accept:$secAccept\r\n\r\n";
        socket_write($client_socket_resource,$buffer,strlen($buffer));
    }

确实有些请求头字段不能从XMLHttpRequest中的javascript修改,所以浏览器的路径被阻塞了?但是,如果有一个浏览器(可能是早期版本)允许修改Sec websocket密钥字段呢?或者如果请求是由一个程序发送以模拟浏览器,那么您完全可以自己构建请求头,从而使Sec websocket密钥失去意义呢?请重新阅读我的回答。即使您编写的服务器或客户端将模拟正确的升级请求,您也会在知道Websockest协议存在的情况下故意这样做。Sec WebSocket键用于过滤意外请求。如果您担心安全性,请使用安全websockets。因此,协议是基于ppl设计的,通常会使用它
<?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 );
?>
function doHandshake($received_header,$client_socket_resource, $host_name, $port) {
        $headers = array();
        $lines = preg_split("/\r\n/", $received_header);
        foreach($lines as $line)
        {
            $line = chop($line);
            if(preg_match('/\A(\S+): (.*)\z/', $line, $matches))
            {
                $headers[$matches[1]] = $matches[2];
            }
        }

        $secKey = $headers['Sec-WebSocket-Key'];
        $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
        $buffer  = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
        "Upgrade: websocket\r\n" .
        "Connection: Upgrade\r\n" .
        "WebSocket-Origin: $host_name\r\n" .
        "WebSocket-Location: ws://$host_name:$port/demo/shout.php\r\n".
        "Sec-WebSocket-Accept:$secAccept\r\n\r\n";
        socket_write($client_socket_resource,$buffer,strlen($buffer));
    }