websocket PHP -流加密启用服务器切断字节

c0vxltue  于 12个月前  发布在  PHP
关注(0)|答案(1)|浏览(104)

我用PHP做了一个WebSocket服务器,并添加了将SSL/TLS添加到服务器的功能。现在我用stream_socket_enable_crypto启用了加密,一切正常。我读取数据并解密。只有HTTP请求有点奇怪:
客户端发送:

GET / HTTP/1.1
Host: example.com:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0
Accept: */*
...

字符串
服务器接收:

HTTP/1.1
Host: example.com:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0
Accept: */*
...


我的问题是:丢失字节的原因是什么?我可以做些什么来找回这些字节?
我使用PHP 8.2

服务器:

终端:

openssl genrsa -out wss.key 2048 && openssl req -key wss.key -new -x509 -days 365 -out wss.crt


PHP:

error_reporting(E_ALL);
ini_set("display_errors", "1");

if(ob_get_level() == 0) ob_start();

$server = stream_socket_server("tcp://example.com:8080", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN);

stream_context_set_option($server, ["ssl" => [
    "local_cert" => __DIR__."/wss.crt",
    "local_pk" => __DIR__."/wss.key",
    "disable_compression" => true,
    "verify_peer" => false,
    "verify_peer_name" => false,
    "allow_self_signed" => true
]]);

$done = false;
while(!$done) {
    $sockets = ["server" => $server];

    if(stream_select($sockets, $w, $e, 0, 20) === false)
        show("ERROR");

    if(in_array($server, $sockets)) {
        $client = stream_socket_accept($server);
        $sockets[] = $client;
        stream_socket_enable_crypto($client, true, STREAM_CRYPTO_METHOD_TLS_SERVER);
    }

    foreach($sockets as $client) {
        if(!in_array($client, $sockets))
            continue;

        show(fread($client, 100));

        fclose($client);
        $done = true;
        show("EXIT");
    }
}

function show(...$data) {
    var_dump($data);
    @ob_flush();
    flush();
}

客户:

JS:

url = "ws://example.com:8080";
socket = new WebSocket(url);
setTimeout(() => {
    socket.close();
    socket = new WebSocket(url);
}, 1000);


使用主机和端口更改example.com:8080
详细代码请参阅PHPWS

uxhixvfz

uxhixvfz1#

我现在知道这个问题了。TCP paylaod开始于00 00之后,在HTTP中开始于GET /,在TLS中开始于TLS headers17 03 03 03 15,TLS数据类型(应用数据23),TLS版本(1.2 03 03)和有效负载长度(789 03 15


的数据



在PHP中,在stream_socket_enable_crypto之后,第一个包被读取为TLS,前5个字节作为TLS头,失败后,因为它的HTTP,它在有效载荷中丢失了这5个字节。

解决方案:

在启用加密之前,读取数据而不从缓冲区(PEEK)中清除数据

if(in_array($server, $sockets)) {
    $client = stream_socket_accept($server);
    $sockets[] = $client;

    $content = stream_socket_recvfrom($client, 5, STREAM_PEEK);

    stream_socket_enable_crypto($client, true, STREAM_CRYPTO_METHOD_TLS_SERVER);
}

字符串
现在,如果数据只是一个HTTP请求,并且在TLS握手时没有丢失TLS头信息,则可以使用该数据。

相关问题