【文章标题】:Hard-Chat – 一款无服务器、仅用RAM的P2P终端聊天工具
【文章正文】: 端到端加密的P2P聊天,直接在浏览器中运行。无需服务器、无需账户、不存储历史记录。 由Hardlint网络安全团队开发 本项目出于教育和安全研究目的分发。它不保证网络层面的匿名性:它保护的是对话内容,而不一定是连接者的身份。在用于敏感通信前,请阅读”攻击面与已知限制”章节。 强烈建议双方设备均使用可信VPN。
- 🔐 端到端加密 —— AES-GCM 256位,通过PBKDF2(10万次迭代)派生密钥
- 🌐 真正的P2P连接 —— 设备间直接建立WebRTC链接,无中心服务器中转消息
- 🚫 零持久化 —— 无cookie、无localStorage、无数据库:关闭标签页即不留痕迹
- 🔑 单一共享密钥 —— 随机生成的100字符房间密钥,无需手动技术配置
- 🧹 紧急清除 —— 一键立即擦除密钥、连接状态和可见聊天记录
- 📡 可靠连接 —— 配置18个STUN/TURN服务器作为后备方案,可在严格NAT环境下工作(4G/5G、企业网络)
使用流程:
- 打开页面(必须通过HTTPS访问——例如GitHub Pages,不能作为本地文件打开)
- 主机方:点击[1]初始化房间 → 复制生成的房间密钥
- 通过其他渠道(当面、语音通话、其他加密应用)将密钥发送给联系人
- 客机方:点击[2]连接到房间 → 粘贴收到的房间密钥
- 等待连接(通常数秒)→ 聊天窗口开启
- 若2分钟内未建立连接,房间密钥自动失效:需使用专用按钮生成新密钥
系统要求:
- 支持WebRTC和Web Crypto API的现代浏览器(最新版Chrome/Firefox/Edge/Safari)
- 双方设备均需联网
- 页面必须通过HTTPS访问(Web Crypto API和WebRTC需要安全上下文)——本地文件打开无效
- 连接尝试期间双方需同时保持页面打开
- 必须完整复制100字符房间密钥,不能有额外空格或换行
技术架构:
Zero-Trace Terminal是静态Web应用(HTML/CSS/JS,无专有后端),通过WebRTC建立设备间直连,交换端到端加密文本消息。
核心组件:
| 组件 | 功能 | 技术实现 |
|---|---|---|
| 用户界面 | 复古终端UI | 纯HTML/CSS |
| 信令系统 | 帮助节点互相发现 | PeerJS(公共云代理) |
| 数据传输 | 加密P2P通道 | WebRTC DataChannel |
| NAT穿透 | 穿越防火墙/NAT | STUN + TURN (ICE) |
| 加密模块 | 消息内容保护 | AES-GCM 256位+PBKDF2 |
| 托管服务 | 代码分发 | GitHub Pages(静态) |
无专有应用服务器:代码完全在用户浏览器中运行。唯一涉及的外部基础设施用于设备间初始”介绍”(信令),以及在无法直连时中继流量(TURN)。
密钥生成机制: 当用户点击”初始化房间(主机)“时:
- 使用加密安全随机数生成器crypto.getRandomValues()(非Math.random())生成100字符随机字符串
- 字符集包含大小写字母、数字和特殊符号(-_!@#$%
该房间密钥是双方需要通过带外方式(如语音消息、当面传递、其他加密通道)交换的唯一共享密钥。从中派生出两个独立值:
A. 消息加密密钥(PBKDF2→AES-GCM)
PBKDF2(
密码=房间密钥,
盐值=“p2p-zero-trace-salt-v1”(固定硬编码),
迭代=100,000次,
哈希算法=SHA-256
) → 256位AES-GCM密钥
B. PeerJS标识符(截断SHA-256)
SHA-256(房间密钥) → 取前32位十六进制字符,加”ztt-”前缀
该ID仅用于双方通过PeerJS信令代理互相发现,不参与加密过程。
关于固定盐值的说明:由于房间密钥本身具有极高熵值(100随机字符),在此场景下使用固定盐值不会削弱安全性——固定盐值仅在弱密码/重复密码场景下存在风险。
连接建立过程:
- 主机创建Peer对象,用派生ID注册到公共PeerJS代理
- 客机粘贴相同房间密钥后,计算相同ID并调用peer.connect(id)
- PeerJS代理仅中介初始连接(谁要与谁通信)——绝不接触消息内容,消息始终通过加密P2P通道传输