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不封顶
信任锚未校验75B
自签名 / 域名不匹配 / 根不受信 / 尚未生效 / 链不完整 / 状态未知60C
已过期45D
总评级与百分制分数映射
总评级分数区间含义
A+≥ 95协议、密钥交换与安全响应头均达到最佳实践
A90 – 94核心安全项达标,仍有少量可优化点
B80 – 89基本合格,存在明显但可修复的短板
C60 – 79多项安全措施缺失,建议尽快整改
D45 – 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 个。范围过大时会直接提示缩小范围,避免拖垮服务器。