test.ssl.sh

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

test.ssl.sh 的每个子域名都只在一个地方“出问题”(或者特别新)。用浏览器打开能看到真实的报错,用 ssl.sh 检查能看到检查结果应该是什么。

最后核实

怎么用

用你要测试的浏览器或 App 打开某个场景,对照下面的预期结果;需要给别人解释时,链接到对应的报错说明页。

测试检查工具本身:运行 curl ssl.sh/<场景>.test.ssl.sh。也可以拿这些地址测试自己的代码和工具:连 expired、self-signed、wrong-host 都不报错的客户端,就是没有校验证书。

证书错误

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

打不开
证书
自签名
服务器配置

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

打不开
证书
实验室私有 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

打不开
证书
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

看客户端
证书
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

看客户端
证书
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

打不开
证书
实验室私有 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

打不开
证书
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

打不开
证书
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

能打开
证书
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

能打开
证书
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

看客户端
证书
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

能打开
证书
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

能打开
证书
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

看客户端
证书
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

打不开
证书
实验室私有 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

能打开
证书
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

能打开
证书
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

能打开
证书
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

打不开
证书
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。

相关

下载

下面这些文件放在 https://test.ssl.sh/downloads/,是故意公开的测试材料,不要用在任何正式环境。

没有做的场景

有些经典测试项目,用现在的 OpenSSL 3 已经做不出来,或者做出来和别的场景报错完全一样。

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 做出来同样只会显示“签发者不受信任”。

靶场是怎么搭的

所有场景跑在同一台 nginx 上。证书类场景只是发送的证书不同;TLS 版本、密钥交换组和客户端证书这类握手参数,nginx 在知道访问的是哪个域名之前就已经确定了,所以这几个场景各自独占一个监听端口,由 443 端口上的 SNI 分流(ssl_preread)转过去。

需要公共可信的场景用 Let's Encrypt 的 6 天短期证书,保证它们只因为想演示的那一个原因出错;私有证书由 sslsh testlab gen 生成。

ssl.sh 主站的 HSTS 故意不带 includeSubDomains,所以访问过 ssl.sh 不会影响 *.test.ssl.sh 的场景:证书错误场景照样有“继续访问”按钮,no-hsts 和 mixed-content 里的 HTTP 请求也不会因为主站的 HSTS 被升级。