# SSL/TLS 测试靶场：20 个故意出错的 HTTPS 测试站点

> test.ssl.sh 下的测试站点：过期、自签名、域名不匹配、缺中间证书、已吊销、TLS 1.0、仅 TLS 1.3、后量子、mTLS，逐个说明浏览器会报什么错、检查结果应该是什么。

Source: https://ssl.sh/zh/test-lab/
Last updated: 2026-11-10

# SSL/TLS 测试靶场：20 个故意出错的 HTTPS 测试站点

test.ssl.sh 下的测试站点：过期、自签名、域名不匹配、缺中间证书、已吊销、TLS 1.0、仅 TLS 1.3、后量子、mTLS，逐个说明浏览器会报什么错、检查结果应该是什么。

## 证书错误

### expired.test.ssl.sh

- 地址: https://expired.test.ssl.sh/
- 证书: Let's Encrypt 6 天证书（不续期）
- 配置: 一张 Let's Encrypt 6 天证书（`shortlived` 配置），只签发一次、不再续期，签发 160 小时后就过期了。
- 浏览器: Chrome、Edge 显示 `NET::ERR_CERT_DATE_INVALID`；Firefox 显示 `SEC_ERROR_EXPIRED_CERTIFICATE`；Safari 提示“此连接不是私人连接”。
- curl ssl.sh/expired.test.ssl.sh: 不通过，给出 `expired`：notAfter 已过，`days_left` 为负数。

### self-signed.test.ssl.sh

- 地址: https://self-signed.test.ssl.sh/
- 证书: 实验室私有 CA
- 配置: `sslsh testlab gen` 生成的自签名证书：签发者就是它自己，没有任何 CA 参与。
- 浏览器: Chrome、Edge 显示 `NET::ERR_CERT_AUTHORITY_INVALID`；Firefox 显示 `MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT`。
- curl ssl.sh/self-signed.test.ssl.sh: 不通过，给出 `self_signed`（链不可信）。直接用 curl 会报 `curl: (60) SSL certificate problem: self-signed certificate`。

### untrusted-root.test.ssl.sh

- 地址: https://untrusted-root.test.ssl.sh/
- 证书: 实验室私有 CA
- 配置: 叶子证书 → 中间证书 → 一个私有根证书（“ssl.sh Test Lab Untrusted Root”），这个根不在任何信任库里，也不对外发布。服务器发送叶子和中间证书。
- 浏览器: Chrome、Edge 显示 `NET::ERR_CERT_AUTHORITY_INVALID`；Firefox 显示 `SEC_ERROR_UNKNOWN_ISSUER`。
- curl ssl.sh/untrusted-root.test.ssl.sh: 不通过，给出 `untrusted_root`。直接用 curl 会报 `curl: (60) SSL certificate problem: self-signed certificate in certificate chain` 或 `unable to get local issuer certificate`。

### wrong-host.test.ssl.sh

- 地址: https://wrong-host.test.ssl.sh/
- 证书: ssl.sh 主站证书
- 配置: 直接使用 ssl.sh 主站自己的有效证书，它只包含 `ssl.sh` 和 `www.ssl.sh`，不包含 `wrong-host.test.ssl.sh`。
- 浏览器: Chrome、Edge 显示 `NET::ERR_CERT_COMMON_NAME_INVALID`；Firefox 显示 `SSL_ERROR_BAD_CERT_DOMAIN`。
- curl ssl.sh/wrong-host.test.ssl.sh: 不通过，给出 `hostname_mismatch`，SAN 列表里只有 `ssl.sh` 和 `www.ssl.sh`。直接用 curl 会报 `no alternative certificate subject name matches target host name`。

### incomplete-chain.test.ssl.sh

- 地址: https://incomplete-chain.test.ssl.sh/
- 证书: Let's Encrypt 6 天证书
- 配置: 证书本身有效，但服务器只发送叶子证书（配置成 `cert.pem` 而不是 `fullchain.pem`），缺了中间证书。
- 浏览器: 浏览器通常能打开：Chrome、Edge、Safari 会按 AIA 地址自动下载缺的中间证书，Firefox 内置了已知中间证书。老安卓设备、App 和命令行工具会失败。
- curl ssl.sh/incomplete-chain.test.ssl.sh: 不通过，给出 `incomplete_chain`。curl、OpenSSL、Python、Node.js 都会报 `unable to get local issuer certificate`。

### revoked.test.ssl.sh

- 地址: https://revoked.test.ssl.sh/
- 证书: Let's Encrypt 90 天证书（已吊销）
- 配置: 一张 Let's Encrypt 90 天证书（`classic` 配置，带 CRL 地址），签发后立即以 keyCompromise 理由吊销，大约每 80 天重新签发并吊销一次。
- 浏览器: Firefox（CRLite）显示 `SEC_ERROR_REVOKED_CERTIFICATE`。Chrome、Edge 只有在序列号进入 Chrome 的 CRLSet 后才显示 `NET::ERR_CERT_REVOKED`，之前照常打开。Safari 取决于苹果的吊销服务。
- curl ssl.sh/revoked.test.ssl.sh: 检查引擎查询 CA 的 CRL 时给出 `revoked`。直接用 curl、OpenSSL 默认不查吊销，会正常连接。

### client-auth-eku.test.ssl.sh

- 地址: https://client-auth-eku.test.ssl.sh/
- 证书: 实验室私有 CA
- 配置: 实验室 CA 签发、扩展密钥用途同时含 serverAuth 和 clientAuth 的证书：公共 CA 已在 2025—2026 年逐步停发这种“多用途”证书。
- 浏览器: 没导入实验室根证书时：`NET::ERR_CERT_AUTHORITY_INVALID` / `SEC_ERROR_UNKNOWN_ISSUER`。导入（带名称约束的）实验室根证书后能正常打开，浏览器不会因为多一个 clientAuth 而拒绝。
- curl ssl.sh/client-auth-eku.test.ssl.sh: 给出 `client_auth_eku`（公共 CA 续期时不会再给同样的 EKU），以及 `untrusted_root`。

## 协议版本与密钥交换

### tls-v1-0.test.ssl.sh

- 地址: https://tls-v1-0.test.ssl.sh/
- 证书: Let's Encrypt 6 天证书
- 配置: 只开 TLS 1.0（`ssl_protocols TLSv1` 加 `@SECLEVEL=0`，OpenSSL 3 在默认安全级别下不允许 TLS 1.0）。
- 浏览器: 当前所有浏览器都拒绝连接：Chrome、Edge 显示 `ERR_SSL_VERSION_OR_CIPHER_MISMATCH`，Firefox 显示 `SSL_ERROR_UNSUPPORTED_VERSION`。
- curl ssl.sh/tls-v1-0.test.ssl.sh: 快速检查给出 `tls_handshake_failed`；完整检查应显示只开了 TLS 1.0。

### tls-v1-1.test.ssl.sh

- 地址: https://tls-v1-1.test.ssl.sh/
- 证书: Let's Encrypt 6 天证书
- 配置: 只开 TLS 1.1（`ssl_protocols TLSv1.1` 加 `@SECLEVEL=0`）。
- 浏览器: 和 TLS 1.0 一样：Chrome、Edge 显示 `ERR_SSL_VERSION_OR_CIPHER_MISMATCH`，Firefox 显示 `SSL_ERROR_UNSUPPORTED_VERSION`。
- curl ssl.sh/tls-v1-1.test.ssl.sh: 快速检查给出 `tls_handshake_failed`；完整检查应显示只开了 TLS 1.1。

### tls-v1-2-only.test.ssl.sh

- 地址: https://tls-v1-2-only.test.ssl.sh/
- 证书: Let's Encrypt 6 天证书
- 配置: 只开 TLS 1.2（`ssl_protocols TLSv1.2`）。
- 浏览器: 所有当前浏览器都能正常打开，协商结果是 TLS 1.2。
- curl ssl.sh/tls-v1-2-only.test.ssl.sh: 通过，`tls_version` 为 TLSv1.2；完整检查会提示没开 TLS 1.3（提示级别，不算错误）。

### tls-v1-3-only.test.ssl.sh

- 地址: https://tls-v1-3-only.test.ssl.sh/
- 证书: Let's Encrypt 6 天证书
- 配置: 只开 TLS 1.3（`ssl_protocols TLSv1.3`）。
- 浏览器: 当前浏览器都能打开。只支持到 TLS 1.2 的客户端（安卓 9 及更早、Windows 10 系统自带的 TLS 组件、较老的 Java 8）会报协议错误。
- curl ssl.sh/tls-v1-3-only.test.ssl.sh: 通过，`tls_version` 为 TLSv1.3；完整检查会显示 TLS 1.2 未开启。

### pq-hybrid-only.test.ssl.sh

- 地址: https://pq-hybrid-only.test.ssl.sh/
- 证书: Let's Encrypt 6 天证书
- 配置: 只开 TLS 1.3，密钥交换组只有后量子混合算法 X25519MLKEM768（`ssl_ecdh_curve X25519MLKEM768`；nginx 必须链接 OpenSSL 3.5 及以上）。
- 浏览器: 较新的 Chrome、Edge、Firefox 和 Safari 26 默认会发送 X25519MLKEM768 密钥份额，可以连上。老浏览器和多数 HTTP 库握手失败（Chrome 显示 `ERR_SSL_VERSION_OR_CIPHER_MISMATCH`）。
- curl ssl.sh/pq-hybrid-only.test.ssl.sh: 检查引擎的 OpenSSL 是 3.5+ 时通过，`key_exchange_group` 为 X25519MLKEM768；OpenSSL 更老时给出 `tls_handshake_failed`。

## HTTP 安全头与页面内容

### hsts.test.ssl.sh

- 地址: https://hsts.test.ssl.sh/
- 证书: Let's Encrypt 6 天证书
- 配置: 证书有效，并发送 `Strict-Transport-Security: max-age=31536000; includeSubDomains`。
- 浏览器: 正常打开。访问过一次后，浏览器会自己把 http:// 改成 https://（Chrome 开发者工具里显示“307 Internal Redirect”），这个域名再出证书错误时也不能点“继续访问”。
- curl ssl.sh/hsts.test.ssl.sh: 通过；完整检查会显示 HSTS，max-age 为 31536000。

### no-hsts.test.ssl.sh

- 地址: https://no-hsts.test.ssl.sh/
- 证书: Let's Encrypt 6 天证书
- 配置: 证书有效，但不发 HSTS 头；HTTP 只用 301 跳到 HTTPS。
- 浏览器: 正常打开，看不出问题。问题在看不见的地方：每次先走明文 HTTP 的第一个请求都可能被劫持（SSL 剥离）。
- curl ssl.sh/no-hsts.test.ssl.sh: 证书检查通过；完整检查会给出 `no_hsts`。

### mixed-content.test.ssl.sh

- 地址: https://mixed-content.test.ssl.sh/
- 证书: Let's Encrypt 6 天证书
- 配置: 一个 HTTPS 页面，里面用明文 `http://` 加载了一张图片和一个脚本。
- 浏览器: Chrome、Edge 拦截脚本、把图片自动升级为 HTTPS，开发者工具控制台会出现“Mixed Content”提示。Firefox 同样拦截脚本。页面上会显示 HTTP 脚本有没有执行。
- curl ssl.sh/mixed-content.test.ssl.sh: 通过：TLS 配置没问题。混合内容是页面问题，不是证书问题，要扫描页面。

## 密钥类型与证书有效期

### long-validity.test.ssl.sh

- 地址: https://long-validity.test.ssl.sh/
- 证书: 实验室私有 CA
- 配置: 实验室 CA 签发、有效期 3650 天的证书。公共可信证书自 2026 年 3 月 15 日起最长 200 天（CA/B 论坛 SC-081 投票），2029 年降到 47 天。
- 浏览器: 没导入实验室根证书时：`NET::ERR_CERT_AUTHORITY_INVALID`。导入后 Chrome、Firefox 能打开（有效期上限只针对公共根），Safari 等苹果客户端仍会拒绝：苹果对有效期超过 825 天的 TLS 证书一律不认，用户自己安装的根也一样。
- curl ssl.sh/long-validity.test.ssl.sh: 不通过，给出 `untrusted_root`；`validity_days` 为 3650，远超公共证书 200 天的上限。

### short-lived-6-days.test.ssl.sh

- 地址: https://short-lived-6-days.test.ssl.sh/
- 证书: Let's Encrypt 6 天证书
- 配置: Let's Encrypt `shortlived` 证书：有效期 160 小时（约 6.7 天），每 2～3 天自动续期。
- 浏览器: 正常打开。
- curl ssl.sh/short-lived-6-days.test.ssl.sh: 通过；`validity_days` 为 7（160 小时向上取整），`days_left` 在 0～6 之间。剩余天数少在这里是正常的，不是续期失败。

### ecc-p256.test.ssl.sh

- 地址: https://ecc-p256.test.ssl.sh/
- 证书: Let's Encrypt 6 天证书
- 配置: 使用 ECDSA P-256 密钥的 Let's Encrypt 证书。
- 浏览器: 正常打开。
- curl ssl.sh/ecc-p256.test.ssl.sh: 通过；`key_type` 为“ECDSA P-256”。

### rsa-4096.test.ssl.sh

- 地址: https://rsa-4096.test.ssl.sh/
- 证书: Let's Encrypt 6 天证书（RSA 4096）
- 配置: 使用 4096 位 RSA 密钥的 Let's Encrypt 证书。
- 浏览器: 正常打开；握手时服务器的计算量比 ECDSA P-256 大，但访问者感觉不到。
- curl ssl.sh/rsa-4096.test.ssl.sh: 通过；`key_type` 为“RSA 4096”。

## 客户端证书

### mtls-required.test.ssl.sh

- 地址: https://mtls-required.test.ssl.sh/
- 证书: Let's Encrypt 6 天证书
- 配置: 服务器要求客户端出示实验室客户端 CA 签发的证书（`ssl_verify_client on`）。测试用客户端证书放在 test.ssl.sh/downloads/。
- 浏览器: 不带客户端证书时，nginx 返回“400 Bad Request — No required SSL certificate was sent”。导入 `client.p12`（密码 `ssl.sh`）后，浏览器会让你选择证书，然后正常打开。
- curl ssl.sh/mtls-required.test.ssl.sh: 服务器证书检查通过。不带客户端证书的 HTTP 请求得到 400；`curl --cert client.pem --key client.key https://mtls-required.test.ssl.sh/` 得到 200。

## 没有做的场景

- RC4: RFC 7465 自 2015 年起禁止在 TLS 中使用 RC4，各浏览器 2016 年已全部移除。OpenSSL 3 只在 legacy provider 里保留 RC4，标准编译的 nginx 无法提供；就算做出来，浏览器里看到的也和 `tls-v1-0` 一样是加密套件不匹配。
- RSA-1024: 公共 CA 十多年前就不签 1024 位 RSA 证书了，大多数发行版自带的 OpenSSL 3 安全级别下 nginx 连这种密钥都加载不了。用私有 CA 做出来，浏览器只会显示“签发者不受信任”，和 `untrusted-root` 重复。
- SSLv3 / SSLv2: POODLE（2014 年）之后各浏览器移除了 SSLv3；OpenSSL 1.1.0 起已经没有 SSLv2，发行版编译时也关掉了 SSLv3。
- SHA-1 signatures: 浏览器 2017 年起不再信任 SHA-1 证书，OpenSSL 3 默认安全级别也拒绝 SHA-1 签名；用私有 CA 做出来同样只会显示“签发者不受信任”。
