You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

浏览器端JS发起安全WebSocket连接失败:证书未知告警问题

问题描述

我的系统包含两台服务器:

  • 一台基于boost::beast的自定义安全WebSocket服务器,监听887端口;
  • 一台标准Apache2 HTTPS服务器,监听443端口,提供以下资源:
    • 引用JavaScript文件的HTML页面;
    • 客户端证书与密钥(已知该方式不安全,但非当前问题重点);
    • 该JavaScript文件尝试使用客户端证书和密钥,连接887端口的安全WebSocket。

预期流程是用户访问该HTML页面后,浏览器自动发起安全WebSocket连接。我已通过openssl s_client验证了安全WebSocket服务器及证书信任链,确认服务器可正确验证客户端证书。但当浏览器运行下方JavaScript代码时,服务器返回‘sslv3 alert certificate unknown’握手错误,拒绝连接。

客户端代码

'use strict'

window.onload = async function () {

  // N.B. all DOM element stuff is purely for debugging purposes.
  const div = document.getElementById('mainContainer');
  div.innerHTML += 'Beginning of life<br />'; 

  const cert_response = await fetch('wss-client.crt');
  const key_response = await fetch('wss-client.key');
  const certVal = await cert_response.text();
  const keyVal = await key_response.text();
  div.innerHTML += certVal + '<p />';
  div.innerHTML += keyVal + '<p />';

  const options = {
    key: keyVal,
    cert: certVal
  };

  let socket = new WebSocket(
          'wss://' + window.location.hostname + ':887',
          ["soap", "wamp", "sip", "amqp", "mqtt", "xmpp"], // I'm guessing here
          options);
  socket.onopen = function(e) {
    div.innerHTML += 'opened socket<br />';
  };
};

我参考了WebSocket类文档(说明options可兼容https.request的参数)及证书指定文档,但本人主要从事C/C++开发,对JavaScript不够精通,可能遗漏了基础要点。


解决方案

你犯了一个关键错误:浏览器端的WebSocket API不支持通过options参数传入客户端证书和密钥。你参考的文档是Node.js环境下的ws库(服务端或Node.js客户端),而非浏览器原生的WebSocket接口。

浏览器处理客户端证书的逻辑完全不同:

  1. 浏览器只会在服务器明确要求客户端证书时,弹出选择框让用户从系统证书存储中选择,无法通过JavaScript代码直接注入证书/密钥。
  2. 你通过fetch获取的证书和密钥文本,无法被浏览器用于TLS握手——浏览器不允许JS直接操作本地证书存储或自定义TLS参数。

修复方案

方案1:使用浏览器证书存储

  • 将客户端证书导入到用户的浏览器(或系统)证书存储中。
  • 确保你的WebSocket服务器配置为请求客户端证书(你已经通过openssl s_client验证过这一点)。
  • 移除代码中的options参数,直接创建WebSocket连接:
let socket = new WebSocket(
  'wss://' + window.location.hostname + ':887',
  ["soap", "wamp", "sip", "amqp", "mqtt", "xmpp"]
);

当浏览器发起连接时,会自动弹出证书选择框,用户选择正确的客户端证书后即可完成握手。

方案2:代理转发(如果必须自动注入证书)

  • 在Node.js环境中搭建一个WebSocket代理服务器,该代理使用ws库加载客户端证书和密钥,转发浏览器的WebSocket请求到目标服务器。
  • 浏览器连接代理服务器(无客户端证书要求),代理服务器与目标服务器建立带客户端证书的WSS连接。

补充说明

你提到的文档是Node.js生态的工具,和浏览器原生API差异极大。浏览器为了安全,严格限制了JS对TLS层的操作权限,这也是你无法通过代码注入证书的核心原因。


内容的提问来源于stack exchange,提问作者Paul Grinberg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 20:55:17