SSL 证书评级标准与评分细则
本页完整公开 ZZSSL 证书检测的判定逻辑:六项计分检测各自的权重、每个等级对应的阈值、总分的计算方式, 以及每一类问题对应的 nginx 修复示例。SNI 仍然检测并展示,但不计入评分,原因见 SNI 章节。你可以先对照规则自查,再用 在线检测 验证整改结果。
总分与总评级
总分采用加权平均而不是简单相加:总分 = Σ(单项得分 × 权重) / Σ(可检测项权重),结果四舍五入取整。
这样设计的原因是不同检测项对实际安全的影响差异很大——「证书可信性」占 28 分,
它决定的是浏览器会不会让用户进得来;PFS、OCSP 与 OCSP Stapling 各占 17 分,
直接决定“加密是否可信、证书是否有效、握手是否高效”;HSTS 占 12 分,TLS 协议配置占 9 分。
六项权重合计 100,分母同为 100,因此分数仍是百分制,不会因为项数变化被系统性拉高或压低。
“可检测项”是一个关键设计:当某项因为环境限制无法探测时(典型场景是服务器没有 openssl 命令行工具,
导致 OCSP Stapling 无法检测;或握手失败、根本没拿到证书,
导致证书可信性无法判定),该项会标记为 -- 并从分母中剔除,
用剩余可检测项的权重重新归一化。这样不会因为环境限制而给出 0 分,避免误导整改方向。
加权平均之外还有一条封顶规则:证书状态会给总分设上限。 证书过期时页面已经打不开了,其余项配得再完美也不该拿到 A/B,所以总分最高 45(D); 自签名、域名不匹配、根证书不受信、尚未生效、证书链不完整、信任状态未知这些情况, 浏览器同样会拦截,总分最高 60(C);只有“信任锚未校验”(链看起来完整、只是核不到公开根)留到 75(C 档)。 分数与评级是一起压的——只压等级会出现「95 分 / C 级」这种自相矛盾的展示。
| 证书信任状态 | 分数上限 | 最高评级 |
|---|---|---|
| 可信(在有效期内) | 100 | 不封顶 |
| 信任锚未校验 | 75 | B |
| 自签名 / 域名不匹配 / 根不受信 / 尚未生效 / 链不完整 / 状态未知 | 60 | C |
| 已过期 | 45 | D |
| 总评级 | 分数区间 | 含义 |
|---|---|---|
| A+ | ≥ 95 | 协议、密钥交换与安全响应头均达到最佳实践 |
| A | 90 – 94 | 核心安全项达标,仍有少量可优化点 |
| B | 80 – 89 | 基本合格,存在明显但可修复的短板 |
| C | 60 – 79 | 多项安全措施缺失,建议尽快整改 |
| D | 45 – 59 | 关键安全项未达标,风险较高 |
| F | < 45 | 存在严重安全缺陷,应立即处理 |
六项计分检测的判定阈值
| 检测项 | 权重 | 判定与得分 |
|---|---|---|
| 证书可信性 | 28 | A+(100) 证书由受信任 CA 签发、覆盖该域名且在有效期内(距到期 > 15 天);A(85) 可信但 ≤ 15 天到期,需尽快续期;C(60) 证书链可构建但信任锚未校验;F(30) 证书链不完整(部分客户端握手失败);F(10) 证书尚未生效;F(0) 已过期 / 自签名 / 域名不匹配 / 根证书不受信任 / 信任状态未知。本项同时决定总评级上限(见下表)。 |
| PFS 前向保密 | 17 | A+(100) 协商 TLSv1.3;A(90) ECDHE + AEAD(GCM/CHACHA20/POLY1305);B(70) DHE(≥2048) 或 ECDHE + CBC;C(50) 仅 RSA 静态密钥交换;D(30) 命中弱套件(RC4/3DES/EXPORT/CBC-SHA1);F(0) 握手失败。 |
| HSTS 严格传输安全 | 12 | A+(100) max-age≥31536000 且 includeSubDomains 且 preload;A(90) max-age≥31536000 且 includeSubDomains;B(75) max-age≥31536000;C(55) max-age≥15552000(180 天);D(30) 已设置但 max-age<180 天或值非法;F(0) 未设置。 |
| OCSP 吊销状态 | 17 | A(100) 查询成功且 Cert Status=good 且 nextUpdate 未过期;B(75) 证书含 AIA OCSP 地址但响应超时/无法解析;C(50) 证书未包含 AIA OCSP 地址;F(0) 状态为 revoked。 |
| OCSP Stapling | 17 | A(100) 返回 stapled 响应且 Cert Status=good 且未过期;B(70) 有 stapled 响应但状态 unknown/已过期/解析失败;C(40) 服务端未启用 stapling(no response sent);D(20) 服务端不支持 status_request 扩展;-- 无 openssl CLI 无法检测。 |
| TLS 协议配置 | 9 | 扣分制:基础分 TLS 1.3 支持 100 / 仅 TLS 1.2 支持 85 / 两者未测出 60 / 两者均不支持 40;每检测到一个开启中的不安全协议再扣分:SSL 2.0 -40(DROWN)、SSL 3.0 -30(POODLE)、TLS 1.0 -20(PCI DSS 要求下线)、TLS 1.1 -10(RFC 8996 已废弃),多个累加、下限 0;等级按 A+≥95 / A≥90 / B≥80 / C≥60 / D≥45 / F<45 映射;未探测到版本标记为 -- 不计入。 |
SNI:多域名站点的第一道关(检测项,不计分)
SNI(Server Name Indication)让客户端在握手阶段就告诉服务端“我要访问哪个域名”,服务端才能返回正确的证书。 检测时我们做三次握手:带目标域名、不带任何 SNI、带一个不存在的域名,然后比对三次返回证书的 SHA-256 指纹与域名匹配情况。
SNI 不计入总分与总评级。原因是 SNI 属于“握手能否成立”的先决条件,不是加密强度维度: “支持 SNI”本身不增加任何加密强度或身份保证,而能否按域名返回正确证书已经由 「证书可信性」这一项(域名不匹配直接判 F,并连带压低总评级)体现。 把同一件事计两次分,会让“服务器有没有按域名正确分流”污染“站点本身有多安全”。
即便如此,我们仍然原样检测并展示它——因为它是排障的第一手线索: 带 SNI 拿到的证书不覆盖目标域名时,说明服务端忽略了 SNI 或证书配置错位,浏览器会直接报证书错误; 只是“不带 SNI 时返回默认证书不匹配”,则只影响不支持 SNI 的老旧客户端。 这三种结果写在检测结果的「证书详情 → 启用 SNI」里,供你排查,不影响上面的六项评分。
server {
listen 443 ssl default_server;
server_name _;
ssl_certificate /etc/nginx/ssl/default.crt;
ssl_certificate_key /etc/nginx/ssl/default.key;
return 444; # 无匹配 SNI 时直接断开
}
PFS:历史流量能否被事后解密
前向保密(Perfect Forward Secrecy)意味着即使服务器私钥某天泄露,攻击者也无法解密此前录制的流量。 实现方式是使用临时密钥交换(ECDHE / DHE),而不是用证书里的 RSA 私钥直接加密预主密钥。 我们的判定顺序是:先看是否协商到 TLS 1.3(强制前向保密,给 A+); 再看套件是否为 ECDHE + AEAD(GCM/CHACHA20/POLY1305,给 A); 接着是 DHE 或 ECDHE + CBC(给 B);仅有 RSA 静态密钥交换时给 C;命中 RC4/3DES/EXPORT/CBC-SHA1 一类弱套件给 D。
ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers off; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305; ssl_ecdh_curve X25519:prime256v1:secp384r1;
HSTS:阻断降级攻击与 Cookie 劫持
没有 HSTS 时,用户第一次输入 http:// 或点击一条 http 链接,请求会以明文发出,
攻击者可以在此刻劫持并降级。HSTS 让浏览器记住“这个域名只能走 HTTPS”,
关键参数是 max-age(记住多久)、includeSubDomains(是否覆盖子域名)与
preload(是否申请写入浏览器内置列表)。我们把 1 年(31536000 秒)作为推荐基线,
180 天(15552000 秒)作为及格线;值为空或非法(例如写成 max-age=abc)判 D。
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
提示:preload 一旦生效很难回退,务必先确认所有子域名都已支持 HTTPS。初次上线建议先用
max-age=300 观察一段时间。
HPKP:已退出评级的机制
HPKP(HTTP Public Key Pinning)曾用于把证书公钥“钉死”,防止 CA 误签发。但它极易因配置错误导致站点长时间不可访问,
已被 Chrome、Edge、Firefox 等主流浏览器移除——也就是说,服务端发不发这个头,对实际安全已经没有任何影响。
因此本系统已把 HPKP 从评级项移除:不计入权重、不参与总分、不作为评级参考,避免把整改精力引向无效工作。
服务端是否发送了 Public-Key-Pins / Public-Key-Pins-Report-Only,
仍会在结果页的「协议详情」中如实列出,供有历史合规需求的场景查阅。
OCSP:证书是不是已经失效
证书被吊销后,浏览器需要一种方式知道它已经作废,否则攻击者可以在私钥泄露后继续使用旧证书。
OCSP 就是在线查询接口,地址写在证书的 authorityInfoAccess 扩展里。
检测时我们从证书里用正则提取 OCSP URI(注意该扩展是多行文本,形如
OCSP - URI:http://ocsp.zuntrust.com),然后真实发起一次查询,解析返回的 Cert Status 与 Next Update。
如果证书压根没写 AIA OCSP 地址,客户端就只能靠 CRL 或短期证书兜底,因此判 C。
常见误区:用 openssl ocsp 查询时出现 Response Verify Failure: unable to get local issuer certificate
是正常现象(缺少 CAfile),只要拿到 OCSP Response Status: successful 与 Cert Status: good 就算查询成功。
OCSP Stapling:把查询结果“钉”在握手中
客户端直连 CA 查询 OCSP 有两个问题:增加握手延迟、把用户访问了哪个站点泄露给 CA。
OCSP Stapling 让服务器自己定期向 CA 取回带签名的 OCSP 响应,并在 TLS 握手的 status_request 扩展里一并下发。
检测方式是 openssl s_client -status:输出 OCSP response: no response sent 表示未启用(判 C);
完全没有任何 OCSP 响应信息,说明服务端连 status_request 扩展都没响应(判 D);
拿到 OCSP Response Status: successful 与 Cert Status: good 且未过期,判 A。
ssl_stapling on; ssl_stapling_verify on; ssl_trusted_certificate /etc/nginx/ssl/chain.pem; resolver 223.5.5.5 119.29.29.29 valid=300s; resolver_timeout 5s;
TLS 协议配置:还开着哪些该关的协议
这一项回答的问题是“服务端到底开放了哪些协议版本”。检测方式是对 SSL 2.0、SSL 3.0、TLS 1.0、TLS 1.1、 TLS 1.2、TLS 1.3 逐个版本独立发起握手(每个版本只声明自己),按服务端真实响应判定, 而不是只看本次协商成功的那一个——协商结果只能说明“服务端挑了哪个”,回答不了“还支持哪些老版本”。
评分采用扣分制:基础分由现代协议决定(TLS 1.3 支持 100 分、仅 TLS 1.2 支持 85 分、两者未测出 60 分、 两者均明确不支持 40 分);每检测到一个开启着的不安全协议再按严重程度扣分—— SSL 2.0 扣 40(DROWN)、SSL 3.0 扣 30(POODLE)、TLS 1.0 扣 20(PCI DSS 已要求下线)、 TLS 1.1 扣 10(RFC 8996 已废弃),多个同时开启时累加,得分下限 0。 状态为“未知”的版本既不扣分也不算支持:没测出来不等于开着,不能把探测失败罚成配置问题。
ssl_protocols TLSv1.2 TLSv1.3; # 只列出保留的版本即可:未列出的 SSL 2.0/3.0、TLS 1.0/1.1 会被直接拒绝握手 # 老版本 OpenSSL(< 1.1.1)不认 TLSv1.3 参数时可先只写 TLSv1.2,并尽快升级 OpenSSL
结果页在评级卡片里直接给出「已开启协议 / 不安全协议(已扣分)/ 未能测出(未扣分)/ 推荐配置」四行结论, 右下角的悬浮快捷入口按主题分组(评测结论 / 证书与部署 / 协议 / 环境与端口), 点击即可定位到对应评级项、证书区块或协议版本明细表;窄屏下入口贴边展开,面板内部滚动,不会挡住正文。
全端口检测的判定
端口扫描与评级是两件事:扫描负责“发现”,评级只针对一个目标端口。系统会先按你选择的方式解析端口清单 (单端口 / 常用 TLS 端口集合 / 自定义范围),用非阻塞批量连接在时间预算内完成连通性探测, 然后对每个开放端口发起 TLS 握手:能握手就标记为 TLS 端口并记录协议、套件与证书信息;不能握手的开放端口 仍然会列在表格里,但标注“非 TLS”,不参与评级。
目标端口的选择规则是:优先使用你指定的首个端口;如果它不是 TLS 端口,则自动退到升序第一个 TLS 端口。 结果页顶部的“主评级端口”就是本次六项评级的实际对象。为防止滥用,单次检测的端口数上限默认 5000 个, 端口扫描整体时间预算默认 20 秒,超出会提示缩小范围或标注“结果可能不完整”。
已知限制与免责声明
- 评级反映的是“检测时刻”的配置状态,CDN 节点众多时不同节点可能返回不同结果。
- OCSP 查询依赖服务器出网能力,内网环境可能因放行策略而失败(此时给 B 而不是 0 分)。
- 缺少 openssl 命令行工具时,OCSP Stapling 无法检测,该项标记为
--并从总分权重中剔除。 - 本工具只做被动读取与握手探测,不进行任何漏洞利用;请仅对自己拥有或已获授权的资产使用。
常见问题
SSL 证书检测的 A+、A、B、C、D、F 分别代表什么?
总分为百分制,由六项检测加权得出(证书可信性、PFS、HSTS、OCSP、OCSP Stapling 与 TLS 协议配置),其中证书状态还会给总分封顶(证书过期最高 45 分/D,证书不可信最高 60 分/C):≥95 为 A+,≥90 为 A,≥80 为 B,≥60 为 C,≥45 为 D,低于 45 为 F。A+ 表示协议版本、密钥交换与安全响应头均达到最佳实践;F 表示存在关键安全缺失。
为什么不再对 HPKP 评级?
HPKP(HTTP Public Key Pinning)已被 Chrome、Edge、Firefox 等主流浏览器移除,服务端是否配置该头已不产生任何实际安全影响,继续评分只会误导整改方向。因此本系统已把 HPKP 从评级项移除:不计入权重、不参与总分、不作为评级参考。服务端有没有发送这个头,仍会在结果页的「协议详情」中如实展示。
OCSP Stapling 显示“无法检测”时总分如何计算?
当服务器缺少 openssl 命令行工具时,OCSP Stapling 无法探测,该项标记为“--”,并从总分权重中剔除,用剩余可检测项的权重重新归一化,不会因为环境限制而给 0 分。
检测结果会被长期保存吗?
不会。本系统不使用 MySQL、SQLite、Redis 等任何数据库,也不做检测统计与榜单:检测报告只写入运行期临时缓存(文件 + flock),默认保留 2 小时、最多 200 份,可随时清空。
为什么默认不能检测内网 IP?
为防止 SSRF(服务端请求伪造)被滥用,系统一律拒绝扫描 10/8、172.16/12、192.168/16、127/8、169.254/16 以及 fc00::/7 等私网与保留地址,页面上也不提供放行开关。如果确实需要巡检内网资产,请在隔离环境中自行部署并改造代码。
检测结果里的服务器环境信息是怎么推断出来的?
系统读取目标在 TLS 握手与 HTTP 响应里披露的内容:Server 头给出服务软件与版本、括号里的平台标记推断操作系统,X-Powered-By 与 Set-Cookie 指出运行时或框架,Via、CF-Ray、X-Amz-Cf-Id 等识别 CDN 与代理,ALPN 与 Alt-Svc 判断 HTTP/2 或 HTTP/3。每一条都标注“确定 / 较可信 / 推测”三档可信度并附原始证据,服务端可以伪造或隐藏这些响应头,因此结论仅供参考。
直接输入 IP 检测和输入域名有什么区别?
输入域名时,系统会以该域名作为 SNI 发起请求,并校验返回的证书是否覆盖该域名,SNI 项能正常评级。只输入 IP 时(例如 1.2.3.4 或 [2400:3200::1]),SNI 机制不适用,该项标记为“--”并从总分分母中剔除,其余各项照常评级。系统会按域名自行解析连接地址,不支持手工指定回源 IP。
全端口检测会不会很慢?
系统使用非阻塞批量连接(stream_select 轮询)扫描端口,单端口连接超时约 1.8 秒,整体时间预算默认 20 秒,端口数上限默认 5000 个。范围过大时会直接提示缩小范围,避免拖垮服务器。
现在就去验证:SSL 证书在线检测