我用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: */*
...

我的问题是:遗漏字节的原因是什么?我可以做些什么来找回这些字节?

我使用的是PHP8.2

Server:

航站楼:

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();
}

Client:

JS:

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

使用您的主机和端口更改example.com:8080

有关详细代码,请参阅PHPWS

推荐答案

我现在知道问题所在了.TCP有效载荷在00 00之后开始,并且在HTTP中以GET /开始,在TLS中以TLS headers:17 03 03 03 15开始,具有TLS数据类型(应用数据23)、TLS版本(1.2 03 03)和有效载荷长度(789 03 15)

HTTP Packet

TLS Packet

在PHP中,stream_socket_enable_crypto之后的第一个包被读取为TLS,前5个字节被读取为TLS头,失败后,由于它是HTTP,它在有效负载中丢失了这5个字节.

Solution:

在启用加密之前,读取数据而不将其从缓冲区中清除(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报头信息,则可以使用该数据.

Php相关问答推荐

自定义WooCommerce查询字符串仅显示前3个产品

PHP cUrl扩展与v8.2.12更新损坏

LaravelEloquent 的地方条件父/子与第三模型多对多

将产品类别添加到WooCommerce产品附加信息

LaravelEloquent 地根据表中的值提取记录

获取并判断WooCommerce用户订阅结束日期

PHP -多维数组到一维数组

在WooCommerce中的本地收件发货方式下添加一个 Select 字段

允许客户定义特定WooCommerce产品的价格

可以';exec、system和shell_exec PHP函数中的命令字符串上的字符数不得超过8175

Regex|PHP捕获json字符串中的每个非法双引号

无法允许元素(img:'src')与symfony html-sanitizer(symfony6.3 php 8.2)

Font Awesome 加载图标未显示在 WooCommerce 管理员列表中

用自定义代码替换 WooCommerce 单一产品简短描述

用于更新 WooCommerce 管理产品列表中库存数量的自定义输入字段

Laravel 10 中的自定义类未找到

从图像URL中获取文件扩展名?

从 CSV 文件 seeder 数据库时的额外行

一个php应用程序可以实例化多个RNG吗

使用 OOP PHP 创建动态 WHERE 子句.如何实现 BETWEEN 运算符?