使用 REST API 监控 SSL 证书过期
检查具有两个 API 端点的任何域的 SSL 证书到期日期、颁发者和安全标头。 包括 GitHub Actions、Node.js 和 Slack 警报示例。
过期的 SSL 证书会使您的网站脱机,并显示令人恐惧的浏览器警告 远去的顾客。 Let's Encrypt 证书自动续订,但 DNS 配置错误,cron 作业失败, 忘记手动证书仍然会导致中断。 您需要一种方法来监控过期时间 您所有域的日期。
botoi API 为此提供了两个端点。 一个返回证书详细信息(颁发者、 有效期、到期日)。 另一个检查 HTTPS 支持并扫描安全性 标头。 它们共同涵盖过期监控和安全态势审计。
使用 /v1/ssl-cert/certificate 获取证书详细信息
此端点连接到域,读取 TLS 证书,并返回结构化的 您可以用任何语言解析的数据。
curl -X POST https://api.botoi.com/v1/ssl-cert/certificate \\
-H "Content-Type: application/json" \\
-d '{"domain": "stripe.com"}'
回复:
{
"success": true,
"data": {
"domain": "stripe.com",
"subject": "CN=stripe.com",
"issuer": "C=US, O=Let's Encrypt, CN=E6",
"valid_from": "2026-02-18T00:00:00.000Z",
"valid_to": "2026-05-19T00:00:00.000Z",
"days_until_expiry": 51,
"serial": "04:A3:9B:7C:2D:1E:8F:00:5A:B2:C4:D6:E8:F0:12:34",
"fingerprint": "A1:B2:C3:D4:E5:F6:78:90:AB:CD:EF:01:23:45:67:89",
"san": ["stripe.com", "*.stripe.com"]
}
}
这 days_until_expiry 字段是您将围绕其构建警报的字段。 这
san 数组显示证书涵盖的所有域,对于验证很有用
通配符证书包含您期望的子域。
使用 /v1/ssl 检查 HTTPS 支持和安全标头
仅仅知道您的证书有效还不够。 您还想确认安全性
HSTS 和 CSP 等标头已就位。 这 /v1/ssl 端点处理这个问题。
curl -X POST https://api.botoi.com/v1/ssl \\
-H "Content-Type: application/json" \\
-d '{"domain": "stripe.com"}'
回复:
{
"success": true,
"data": {
"domain": "stripe.com",
"ssl_supported": true,
"protocol": "TLSv1.3",
"headers": {
"strict-transport-security": "max-age=63072000; includeSubDomains; preload",
"content-security-policy": "default-src 'self'; script-src 'self' js.stripe.com",
"x-frame-options": "SAMEORIGIN",
"x-content-type-options": "nosniff",
"referrer-policy": "strict-origin-when-cross-origin"
}
}
}
这 ssl_supported 布尔值确认 HTTPS 有效。 这 headers
对象表面 HSTS、CSP、X-Frame-Options、X-Content-Type-Options 和 Referrer-Policy。
缺少标头表明您的安全配置存在缺陷。 1.2 以下的 TLS 协议
是一个危险信号。
GitHub Actions:每周检查自动创建的问题
此工作流程每周一运行,检查域列表,并在以下情况下打开 GitHub 问题:
任何证书都会在 30 天内过期。 创造
.github/workflows/ssl-check.yml:
name: SSL Expiry Check
on:
schedule:
# Every Monday at 9:00 UTC
- cron: '0 9 * * 1'
workflow_dispatch:
jobs:
check-ssl:
runs-on: ubuntu-latest
steps:
- name: Check SSL certificates
run: |
DOMAINS=("stripe.com" "api.stripe.com" "dashboard.stripe.com")
THRESHOLD=30
FAILURES=""
for DOMAIN in "\\\${DOMAINS[@]}"; do
RESPONSE=\$(curl -s -X POST https://api.botoi.com/v1/ssl-cert/certificate \\
-H "Content-Type: application/json" \\
-d "{\\"domain\\": \\"\$DOMAIN\\"}")
DAYS=\$(echo "\$RESPONSE" | jq -r '.data.days_until_expiry')
ISSUER=\$(echo "\$RESPONSE" | jq -r '.data.issuer')
EXPIRY=\$(echo "\$RESPONSE" | jq -r '.data.valid_to')
echo "## \$DOMAIN" >> \$GITHUB_STEP_SUMMARY
echo "- Expires: \$EXPIRY" >> \$GITHUB_STEP_SUMMARY
echo "- Days left: \$DAYS" >> \$GITHUB_STEP_SUMMARY
echo "- Issuer: \$ISSUER" >> \$GITHUB_STEP_SUMMARY
echo "" >> \$GITHUB_STEP_SUMMARY
if [ "\$DAYS" -lt "\$THRESHOLD" ]; then
FAILURES="\$FAILURES\\n- \$DOMAIN expires in \$DAYS days (\$EXPIRY)"
fi
done
if [ -n "\$FAILURES" ]; then
echo "::error::Certificates expiring within \$THRESHOLD days:\$FAILURES"
exit 1
fi
echo "All certificates have more than \$THRESHOLD days remaining."
- name: Open GitHub issue on failure
if: failure()
uses: actions/github-script@v7
with:
script: |
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: 'SSL certificate expiring soon',
body: 'The weekly SSL check found certificates expiring within 30 days. See the [workflow run](' + context.serverUrl + '/' + context.repo.owner + '/' + context.repo.repo + '/actions/runs/' + context.runId + ') for details.',
labels: ['infrastructure', 'urgent']
});
工作流循环遍历每个域、查询 API 并累积失败。 如果
任何证书低于 30 天阈值,作业都会失败并创建 GitHub
问题已标记 infrastructure 和 urgent。 工作总结显示
每个域的完整报告。
调整 DOMAINS 和 THRESHOLD 以匹配您的设置。 自由的
层每天最多处理 100 个请求,涵盖每周检查的约 14 个域。
Node.js:监控脚本中的多个域
为了集成到您自己的监控堆栈中,这里有一个 Node.js 脚本,用于检查 并行的域数组并标记证书即将到期:
const DOMAINS = [
"stripe.com",
"api.stripe.com",
"dashboard.stripe.com",
"docs.stripe.com",
];
const THRESHOLD_DAYS = 30;
async function checkCert(domain) {
const res = await fetch("https://api.botoi.com/v1/ssl-cert/certificate", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": process.env.BOTOI_API_KEY,
},
body: JSON.stringify({ domain }),
});
const { data } = await res.json();
return { domain, ...data };
}
async function checkAll() {
const results = await Promise.all(DOMAINS.map(checkCert));
const expiring = results.filter(
(r) => r.days_until_expiry < THRESHOLD_DAYS
);
console.log("SSL Certificate Report");
console.log("=".repeat(50));
for (const r of results) {
const status =
r.days_until_expiry < THRESHOLD_DAYS ? "WARNING" : "OK";
console.log(
\`[\\\${status}] \\\${r.domain} - \\\${r.days_until_expiry} days left (expires \\\${r.valid_to})\`
);
}
if (expiring.length > 0) {
console.log(
\`\\n\\\${expiring.length} certificate(s) expiring within \\\${THRESHOLD_DAYS} days.\`
);
}
return { results, expiring };
}
checkAll();
按 cron 计划运行它或将其集成到现有的运行状况检查管道中。
这 Promise.all 调用同时检查所有域,因此总计
执行时间接近单个 API 调用的延迟。
证书即将过期时 Slack Webhook 发出警报
将证书检查与 Slack 传入 Webhook 配对,以便在出现问题时通知您的团队 证书需要注意:
async function sendSlackAlert(domain, daysLeft, validTo) {
const webhookUrl = process.env.SLACK_WEBHOOK_URL;
await fetch(webhookUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text: \`:rotating_light: SSL certificate for \\\${domain} expires in \\\${daysLeft} days\`,
blocks: [
{
type: "section",
text: {
type: "mrkdwn",
text: [
"*SSL Certificate Expiry Warning*",
\`Domain: \\\`\\\${domain}\\\`\`,
\`Days remaining: *\\\${daysLeft}*\`,
\`Expires: \\\${validTo}\`,
].join("\\n"),
},
},
],
}),
});
}
// After running the certificate check
async function checkAndAlert() {
const DOMAINS = ["stripe.com", "api.stripe.com"];
for (const domain of DOMAINS) {
const res = await fetch(
"https://api.botoi.com/v1/ssl-cert/certificate",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": process.env.BOTOI_API_KEY,
},
body: JSON.stringify({ domain }),
}
);
const { data } = await res.json();
if (data.days_until_expiry < 30) {
await sendSlackAlert(domain, data.days_until_expiry, data.valid_to);
}
}
}
checkAndAlert();
该消息包括域、剩余天数和到期日期。 您的团队看到 Slack 中发出警报,可以在证书过期之前进行调查。
全面的安全审计:结合两个端点
为了获得完整的画面,请按域并行运行两个端点。 这给你 一次传递证书过期数据和安全标头覆盖范围:
async function auditSsl(domain) {
const [cert, ssl] = await Promise.all([
fetch("https://api.botoi.com/v1/ssl-cert/certificate", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": process.env.BOTOI_API_KEY,
},
body: JSON.stringify({ domain }),
}).then((r) => r.json()),
fetch("https://api.botoi.com/v1/ssl", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": process.env.BOTOI_API_KEY,
},
body: JSON.stringify({ domain }),
}).then((r) => r.json()),
]);
const issues = [];
// Certificate checks
if (cert.data.days_until_expiry < 30) {
issues.push(\`Certificate expires in \\\${cert.data.days_until_expiry} days\`);
}
// Security header checks
const headers = ssl.data.headers || {};
if (!headers["strict-transport-security"]) {
issues.push("Missing HSTS header");
}
if (!headers["content-security-policy"]) {
issues.push("Missing Content-Security-Policy header");
}
if (!headers["x-frame-options"]) {
issues.push("Missing X-Frame-Options header");
}
return { domain, cert: cert.data, ssl: ssl.data, issues };
}
// Run audit across all domains
const domains = ["stripe.com", "api.stripe.com"];
Promise.all(domains.map(auditSsl)).then((results) => {
for (const r of results) {
console.log(\`\\n\\\${r.domain}:\`);
console.log(\` Certificate: \\\${r.cert.days_until_expiry} days left\`);
console.log(\` TLS: \\\${r.ssl.protocol}\`);
console.log(\` Issues: \\\${r.issues.length === 0 ? "None" : r.issues.join(", ")}\`);
}
});
此脚本报告证书到期、TLS 协议版本和缺失的安全性 每个域的标头。 将其添加到您的每周安全审查中或将其连接到您的 事件响应仪表板。
要点
-
/v1/ssl-cert/certificate返回发行人、有效期、days_until_expiry、序列号、指纹和任何 SAN 列表 域的 TLS 证书。 -
/v1/ssl检查 HTTPS 支持,报告 TLS 协议版本,以及 扫描 HSTS、CSP、X-Frame-Options、X-Content-Type-Options 和 Referrer-Policy 标头。 -
两个端点均以每分钟 5 个请求的速度匿名工作。 通过一个
X-Api-Key更高限制的标头。 - 具有 30 天阈值的每周 GitHub Actions cron 作业会捕获续订失败 在停电之前。
- 组合两个端点以运行证书过期监控和安全标头 在单个脚本中进行审核。
FAQ
- 如何通过 API 检查 SSL 证书是否过期?
- 使用包含域的 JSON 正文向 https://api.botoi.com/v1/ssl-cert/certificate 发送 POST 请求。 响应包括证书的 valid_from、valid_to 和 days_until_expiry 字段。 无需 openssl CLI 或手动浏览器检查。
- /v1/ssl-cert/certificate 和 /v1/ssl 有什么区别?
- /v1/ssl-cert/certificate 端点返回证书详细信息:颁发者、主题、序列号、有效期和到期天数。 /v1/ssl 端点检查是否支持 HTTPS 并扫描 HSTS、CSP、X-Frame-Options 和 Referrer-Policy 等安全标头。 使用第一个进行过期监控,第二个用于安全审核。
- 我可以在没有 API 密钥的情况下检查 SSL 证书吗?
- 是的。 匿名访问允许每分钟 5 个请求和每天 100 个请求,并具有基于 IP 的速率限制。 无需注册或 API 密钥。 如需更高吞吐量,付费计划起价为 9 美元/月。
- 我应该多久检查一次 SSL 证书过期情况?
- 对于大多数团队来说,每周是一个很好的基准。 Let's Encrypt 证书每 90 天更新一次,并在到期前 30 天自动更新。 每周检查一次,警告阈值为 30 天,让您有足够的时间在证书过期之前修复续订失败。
- 这适用于自签名或内部证书吗?
- API 通过公共互联网连接到域,因此它可以与端口 443 上提供的任何证书配合使用。自签名证书将返回证书详细信息,但颁发者字段将显示自签名实体而不是受信任的 CA。
开始使用 botoi 构建
150+ 个 API 端点,涵盖查询、文本处理、图片生成和开发者工具。免费套餐,无需信用卡。