systemslibrarian/crypto-lab-ssh-handshake

GitHub: systemslibrarian/crypto-lab-ssh-handshake

基于浏览器的 SSH 握手协议交互式教学演示,用于直观展示 X25519/Ed25519 密钥交换、known_hosts TOFU 信任机制及 MITM 检测原理。

Stars: 0 | Forks: 0

# crypto-lab-ssh-handshake ## 它是什么 这是一个用于演示 **SSH 传输层握手** 以及用于认证服务器的 **`known_hosts` / 首次使用信任 (Trust-On-First-Use, 简称 TOFU)** 流程的交互式模型。服务器持有一个长期主机密钥;每次连接时,双方都会生成全新的临时 ECDH 密钥;服务器对一个单一的“交换哈希”进行签名——这是一个通过 SHA-256 将主机名、主机公钥、双方的临时公钥以及共享密钥绑定在一起的哈希——以此证明其拥有该主机私钥,随后客户端会验证该签名,并将主机指纹与其 `known_hosts` 中的固定记录进行比对。这里使用的是真实的加密算法:用于密钥协商的临时 **X25519**(带有自动回退至 **ECDH P-256** 的机制),以及用于主机签名的 **Ed25519**(带有自动回退至 **ECDSA P-256** 的机制),所有这些均通过 Web Crypto API 实现。SSH 以此解决的问题正是**认证一台你既没有 CA 路径也没有信任网络路径可达的服务器**:首次连接会固定主机密钥(一次未经证实的信仰之跃),而之后的每次连接都会检测密钥是否发生了更改——该模型让你无需中心化机构即可获得具备前向保密性的会话和变更检测能力。该模型**刻意不去**模拟的部分包括:SSH 二进制数据包协议、RFC 4253 算法协商、通道或用户认证:这里使用的消息都是普通的 JSON 对象。这是一个对传输安全和信任逻辑的忠实模型,而不是对 OpenSSH 线上传输格式的重新实现。 ## 何时使用它 - **理解 SSH 的主机密钥提示** —— 准确看清当客户端打印出 `The authenticity of host '…' can't be established` 和一个指纹时,它实际上被要求确认的是什么。演示的 `ask` 模式会回滚引擎的自动固定机制,因此你必须亲自去接受、拒绝或带外验证该指纹。 - **分析 `known_hosts` 警告** —— 当出现 `REMOTE HOST IDENTIFICATION HAS CHANGED!` 时,底层发生的就是这种情况。记录检查器会高亮显示破坏了握手的字段(主机公钥、签名等),这样你就能看出到底是检查的*哪*一部分被触发了。 - **对比三种信任模型** —— 结合同系列的其他演示阅读:[`crypto-lab-pki-chain`](https://systemslibrarian.github.io/crypto-lab-pki-chain/)(层级化 CA / TLS)和[`crypto-lab-web-of-trust`](https://systemslibrarian.github.io/crypto-lab-web-of-trust/)(去中心化 PGP)。SSH 介于两者之间:没有 CA,没有关系图,只有基于单台主机的固定记录 —— 除非你选择使用 SSHFP+DNSSEC 或 OpenSSH 的 `@cert-authority`,这些在演示中也有建模。 - **教学:临时密钥交换 (KEX) + 签名认证** —— 同样的结构也出现在 TLS 1.3 和 Noise 中;SSH 是观察这一过程最清晰的地方,因为中间没有证书机制的阻碍。 - **比较 `StrictHostKeyChecking` 模式** —— 在 `yes`(拒绝未知主机)、`ask`(提示)、`accept-new`(静默固定,拒绝更改)和 `no`(信任任何响应者)之间切换,观察同一次连接是如何产生截然不同的决策的。 - **绝对不要用这个来评估生产环境中的首次接触安全性** —— TOFU **无法**保护首次连接免受主动的中间人攻击。演示中专门包含了*首次接触时的 MITM* 和*在没有 DNSSEC 的情况下对 SSHFP 进行 DNS 欺骗*的场景,正是为了让这一局限性无可辩驳。 - **绝对不要将其作为真实的 SSH 实现** —— 这是一个用于学习的玩具。在生产环境中请使用 OpenSSH、libssh 或其他经过严格审查的库。 ## 在线演示 [**https://systemslibrarian.github.io/crypto-lab-ssh-handshake/**](https://systemslibrarian.github.io/crypto-lab-ssh-handshake/) 该页面分为六个部分进行演示。 * **启动服务器** 会在你的浏览器中生成一个真实的主机密钥对,并显示其 `SHA256:` 指纹。这里还提供了两种可选的信任引导机制:发布 **SSHFP DNS 记录**(带有 DNSSEC 开关,RFC 4255)以及启动一个 **OpenSSH 主机 CA**,它可以对主机的公钥进行签名,从而让客户端通过 `@cert-authority` 信任该 CA,而无需固定每一台主机。 * **连接** 运行握手过程。一个 `StrictHostKeyChecking` 选择器让你可以挑选 `yes` / `ask` / `accept-new` / `no` —— `ask` 会产生一个明确的 接受 / 拒绝 / 带外验证 / 通过 SSHFP 验证 的提示,而不是静默固定。每次握手都会暴露一个完整的记录检查器(客户端和服务器临时密钥、主机公钥、交换哈希、签名、决策),支持复制为 JSON;破坏连接的字段会被高亮显示。固定记录列表旁边有一个逼真的 `~/.ssh/known_hosts` 文件视图,以及 `ssh-keygen -F` 和 `ssh-keygen -R` 的输出。**重置所有内容** 控件可以将演示恢复到初始状态。 * **破坏它(并恢复)** 运行八个场景 —— *固定后的 MITM*(被 known_hosts 捕获)、*首次接触时的 MITM*(TOFU 固定了攻击者 —— 诚实的局限性)、*篡改主机签名*(签名验证触发拦截)、*在没有 DNSSEC 的情况下对 SSHFP 进行 DNS 欺骗*(“带外验证”路径在撒谎)、*恶意 CA 签名攻击者的主机*(被拒绝,因为恶意 CA 不是信任锚点),以及三个操作场景:*计划内的密钥轮换*、*紧急轮换*,以及*在同一 CA 下轮换主机*(唯一一个连接时没有警告的场景)。每个场景都有一个“复制摘要为 Markdown”的按钮,方便分享。 * **三种信任模型** 比较了层级化 PKI、信任网络 和 SSH TOFU,并带有链接到同系列其他演示的“三大演示中的首次接触”标注。 * **现实世界中** 记录了 `~/.ssh/known_hosts`、`SHA256:` 指纹、主机密钥类型、SSHFP DNS 记录、基于证书的 SSH 以及 `StrictHostKeyChecking` 模式,并配有诚实客观的“TOFU 教会了我们什么”卡片。 * **范围与出处** 详细说明了演示忠实模拟了什么,以及刻意省略了什么,并提供了指向 RFC 4251 / 4253 / 4255 / 5656、OpenSSH `PROTOCOL.certkeys` 以及相关 `man` 页面的链接。 该 URL 支持 `?scenario=` 用于深层链接 —— 例如,`?scenario=mitm-after` 会自动启动服务器,固定一次合法主机,然后触发固定后 MITM 场景。 ## 如何在本地运行 ``` git clone https://github.com/systemslibrarian/crypto-lab-ssh-handshake.git cd crypto-lab-ssh-handshake npm install npm run dev # local dev server with HMR npm run build # type-check + production build to dist/ npm run preview # serve the built dist/ locally npm test # vitest — 40 unit tests (engine, policy, wire format, SSHFP, CA) npm run test:e2e # playwright — 13 browser tests for the teaching flows (needs `npx playwright install chromium`) ``` 不需要环境变量,不需要 API 密钥,也不需要后端服务器。所有操作都在浏览器的客户端运行。`src/engine.ts` 中的引擎是构建提示词中一字不差的源代码;唯一事后的改进是 `fingerprint()`,它现在会对规范化的 OpenSSH 线上传输格式公钥数据块(通过 `src/wire.ts`)进行哈希处理,而不是拼接 JWK 坐标,这使得演示中打印的 `SHA256:` 字符串能够与 `ssh-keygen -lf` 打印出来的结果保持一致。其他模块 —— `src/policy.ts` 中的 StrictHostKeyChecking 策略、`src/sshfp.ts` 中的 SSHFP 注册表、`src/ca.ts` 中的主机 CA、`src/transcript.ts` 中的记录捕获 —— 都构建在引擎之上,而不会触及引擎底层的加密逻辑。 ## Crypto-Lab 套件的一部分 这是一个更庞大的交互式密码学实验室演示组合中的一个 —— 请访问 [systemslibrarian.github.io/crypto-lab](https://systemslibrarian.github.io/crypto-lab/) 查看其他项目,包括五大 PQC 家族概述、混合 TLS、现在获取以后解密的时间线,以及对各个独立方案的深入分析。 “所以,你们或吃或喝,或做任何事,都要为神的荣耀而行。” —— 哥林多前书 10:31
标签:SSH协议, Web Crypto API, 前端可视化, 密码学教学, 密钥交换, 暗色界面, 特征检测, 自动化攻击