PHP不原生支持WebSocket客户端加密,wss://依赖底层TLS实现全连接加密,手动对消息体AES加密会破坏WebSocket帧格式且增加安全风险;正确做法是配置stream_socket_client()启用证书校验的TLS。
PHP 本身不原生支持 WebSocket 客户端连接,更不内置 WebSocket 加密协商逻辑;所谓“PHP 连接 WebSocket 加密”,实际是靠 stream_socket_client() 或第三方库(如 Ratchet、ReactPHP)走 wss:// 协议,依赖底层 TLS 实现加密,而非 PHP 层手动加解密。
WebSocket 握手和帧格式有严格规范。手动对 payload 做 AES 加密后直接发送,会导致:
wss:// 已是标准方案:TLS 在 TCP 之上加密整个连接(包括 HTTP 握手 + 所有 WebSocket 帧),无需你碰字节级帧结构stream_socket_client() 连 wss:// 的关键配置PHP 原生方式仅适用于简单场景(如发一条消息后关闭)。必须显式启用 TLS,并校验证书:
$context = stream_context_create([ 'ssl' => [ 'verify_peer' => true, 'verify_peer_name' => true, 'cafile' => '/path/to/root-ca.crt', // 必须提供可信 CA 证书链 'SNI_enabled' => true, ] ]); $socket = stream_socket_client('wss://example.com:443/ws', $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context); if (!$socket) { die("SSL connect failed: $errstr ($errno)"); }
常见坑:
verify_peer => false 绝对禁止用于生产——等于放弃中间人攻击防护cafile 且系统 CA 路径不可读时,stream_socket_client() 会静默失败(尤其 Alpine Linux 容器)wss:// 地址不能带查询参数(如 wss://a.com/ws?token=xxx),部分服务端不解析;应改用握手时在 Sec-WebSocket-Protocol 或首帧中传 tokenRatchet 或 ReactPHP 时 TLS 怎么配?这些库本质还是封装 stream_socket_server() / stream_socket_client(),TLS 配置点相同:
Ratchet 客户端(如 Thruway)需传入 tls 选项对象,内部映射到 ssl contextReactPHP 的 Connector 构造时传 ['tls' => ['cafile' => '...']]
真正要防的是传输被嗅探或篡改,wss:// + 正确证书验证已足够;自己在 PHP 层对每条消息 AES 加密,既无必要,又容易因密钥分发、IV 管理、填充方式等引入新风险。