参考
ssl.sh JSON API:证书检查、证书链、CT、CAA、HSTS 接口
ssl.sh 的 API 是 https://ssl.sh/api/v1/ 下的一组只读 JSON 接口。用 GET 请求、把域名放在查询参数里即可,日常使用不需要注册。
认证和额度
- 匿名:每个 IP 每分钟 30 次检查(令牌桶)。结果缓存 5 分钟(失败结果 1 分钟),命中缓存不计次数。
- API Key:请求头带
Authorization: Bearer <key>(或参数?key=<key>),额度按套餐。Key 无效返回401 invalid_key。 - 超出额度:返回
429 rate_limited,Retry-After头给出需要等待的秒数。 - 检查类接口加
fresh=1跳过缓存(会计入次数)。
错误格式
所有错误都是同一个结构:
{"error": "blocked_address", "message": "10.0.0.1 resolves to 10.0.0.1: private or reserved range 10.0.0.0/8"}
| 状态码 | error 取值 |
|---|---|
| 400 | missing_host、invalid_host、invalid_port、port_not_allowed、invalid_starttls、private_key_rejected、parse_failed |
| 401 | invalid_key |
| 403 | blocked_address(内网、回环、链路本地、100.64.0.0/10 或其他保留地址) |
| 404 | not_found |
| 413 | too_large |
| 429 | rate_limited |
| 502 | dns_failed、connect_refused、connect_failed、timeout、tls_handshake_failed、protocol_mismatch、starttls_failed、ct_unavailable、fetch_failed |
/api/v1/check 返回 502 时,响应体仍是完整的检查结果(含 error、error_detail、message),可以据此区分是 DNS 解析失败还是端口不通。message 目前是英文;中文说明在 findings[].message_zh 里。
GET /api/v1/check
检查一个主机。参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
host |
必填 | 域名、域名:端口 或网址。 |
port |
443 | 允许:443、8443、4443、9443、10443、465、587、25、993、995、143、110、21、990、636、853、5222、5432、6443、2083、2087、8883。 |
starttls |
自动 | smtp、imap、pop3、ftp、xmpp、postgres。25、587、143、110、21、5222、5432 端口自动启用。 |
full |
关 | full=1 再逐个测试 TLS 版本、HSTS、CAA 和吊销状态。 |
fresh |
关 | fresh=1 跳过缓存。 |
curl -s 'https://ssl.sh/api/v1/check?host=example.com&full=1'
返回(节选):
{
"host": "example.com",
"port": 443,
"ip": "203.0.113.10",
"ok": true,
"error": null,
"tls_version": "TLSv1.3",
"cipher": "TLS_AES_256_GCM_SHA384",
"alpn": "h2",
"protocols": {"TLSv1.0": false, "TLSv1.1": false, "TLSv1.2": true, "TLSv1.3": true},
"chain": [
{
"subject_cn": "example.com",
"sans": ["example.com", "www.example.com"],
"issuer_cn": "R12",
"issuer_org": "Let's Encrypt",
"not_after": "2027-01-13T07:11:59Z",
"days_left": 64,
"key_type": "RSA 2048",
"validation_level": "DV",
"pem": "-----BEGIN CERTIFICATE-----\n…"
}
],
"chain_complete": true,
"trusted": true,
"hostname_match": true,
"hsts": "max-age=31536000; includeSubDomains",
"caa": ["0 issue \"letsencrypt.org\""],
"revocation": "good",
"findings": [
{"level": "ok", "code": "valid", "message": "Certificate is valid and trusted, expires in 64 days.", "message_zh": "证书有效且受信任,64 天后过期。", "link": null}
],
"grade": "A+",
"days_left": 64,
"fullchain_pem": "-----BEGIN CERTIFICATE-----\n…",
"report_url": "https://ssl.sh/example.com"
}
字段说明:
chain是服务器实际发送的顺序;aia_fetched是服务器没发、由 ssl.sh 按 AIA 下载的中间证书,它不为空时chain_complete为false。findings[].code供程序判断:expired、not_yet_valid、expires_soon、hostname_mismatch、self_signed、untrusted_root、incomplete_chain、revoked、weak_key、sha1、tls10_enabled、tls11_enabled、weak_cipher、legacy_only、no_tls13、no_hsts、hsts_short、caa_missing、client_auth_eku。link是对应的解决办法页面(中文页面在前面加/zh)。grade为A+、A、B、C、F或T(不受信任);握手都没成功时为null。protocols、hsts、caa、revocation只在full=1时有值;key_exchange_group取不到时为null。
GET /api/v1/chain
返回补齐后的证书链:{host, port, trusted, chain_complete, root, pem_fullchain, certs: [...]}。pem_fullchain 按验证路径排列(站点证书在前,中间证书在后,不含根证书);certs 每项字段同上,另有 source:server(服务器发送)或 aia(补齐下载)。
curl -s 'https://ssl.sh/api/v1/chain?host=example.com' | jq -r .pem_fullchain > fullchain.pem
GET /api/v1/ct
查询证书透明度日志,先查 crt.sh,失败时改查 Cert Spotter,结果缓存 6 小时。可以用来发现别人用你的域名申请的证书。
| 参数 | 默认值 | 说明 |
|---|---|---|
domain |
必填 | 域名。 |
include_subdomains |
1 | 0 只查这个域名本身。 |
include_expired |
0 | 1 包含已过期的证书。 |
每条记录:{id, issuer, not_before, not_after, dns_names, serial, source},按 not_before 倒序。
GET /api/v1/caa
?domain=example.com 返回生效的 CAA 记录:按 RFC 8659 从该域名逐级往上找,第一个有记录的名字生效。返回 {domain, found_at, records, issue, issuewild, iodef, any_ca_allowed}。阿里云、腾讯云 DNSPod 的解析控制台都支持添加 CAA 记录。
GET /api/v1/hsts
?host=example.com 请求 https://example.com/,返回 {host, port, http_status, header, max_age, max_age_days, include_subdomains, preload_directive, preload_list}。preload_list 是 hstspreload.org 接口给出的预加载状态(preloaded、pending、unknown 等),该服务无响应时为 null。
GET /api/v1/mixed-content
?url=https://example.com/page(或 ?host=)下载页面(最多 2 MB,跟随跳转),列出用 http:// 加载的子资源:{url, final_url, status, page_is_https, count, active, passive, insecure_forms, items: [{tag, attr, url, type}]}。active(脚本、样式表、iframe)会被浏览器直接拦截,passive(图片、音视频)会让地址栏显示不安全。详见混合内容警告。
POST /api/v1/decode
在请求体里发送证书或 CSR,PEM 或 base64 DER 都可以(纯文本、JSON {"pem": "…"} 或表单字段 pem),最大 256 KB。只要内容里出现 PRIVATE KEY 就返回 400 private_key_rejected,不做任何处理。私钥不要发给任何在线工具。
curl -s https://ssl.sh/api/v1/decode --data-binary @cert.pem
证书返回 {"type": "certificate", "count": n, "certificates": [...]},字段同 chain;CSR 返回 {"type": "csr", "csr": {subject, subject_cn, sans, key_type, sig_alg, signature_valid}}。
常见问题
有没有官方 SDK?
不需要 SDK:所有接口都是普通的 GET 请求(解析证书是一个 POST),返回 JSON。curl、Python 的 requests、Node 的 fetch、Go 的 net/http 都能直接调。
国内服务器调用会不会很慢?
检查本身需要 ssl.sh 连接你的目标主机,耗时主要取决于目标服务器的响应速度,通常 1~3 秒。CT 查询依赖 crt.sh 等海外服务,第一次可能要十几秒,之后 6 小时内走缓存。