分享一个 SSL 证书监控网站的开发经验 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yeahjw
V2EX    分享发现

分享一个 SSL 证书监控网站的开发经验

  •  
  •   yeahjw 7 天前 703 次点击

    最近做了一个 简单的 SSL 证书监控网站,想和大家分享一些开发过程中的经验。项目地址放在最后了,先聊聊技术实现。

    起因

    之前遇到过几次 SSL 证书过期导致服务中断的情,每次都是用户发现后才去处理,很被动。市面上有一些监控工具,但要么太重,要么功能不够用,就想着自己做一个。

    技术选型

    Next.js 16 + shadcn/ui + TypeScript

    选 Next.js 是因为:

    • App Router 的开发体验很好,路由和文件结构对应
    • Server Components 减少了客户端 Javascript
    • 内置的图片优化、字体加载等开箱即用

    shadcn/ui 是基于 Radix UI 的组件库,优点是:

    • 组件复制到项目中,完全可控
    • 使用 Tailwind CSS ,样式定制方便
    • Accessibility 做得很好

    Drizzle ORM + PostgreSQL

    之前用过 Prisma ,这次试了 Drizzle ,感觉更轻量:

    • 类型生成更快
    • SQL 操作更直观
    • 查询性能更好

    better-auth 认证系统

    这个是最近发现的,比 NextAuth 更新:

    • TypeScript 支持更好
    • API 设计更简洁
    • 支持邮箱密码 + 多种 OAuth ( GitHub 、Google )

    guardssl

    遇到的一些坑

    1. 证书链验证的复杂性

    一开始以为 SSL 证书检查很简单,就是获取证书信息。后来发现证书链验证很复杂:

    • 需要验证每个证书的签名
    • 检查证书链的完整性
    • 判断根证书是否可信(浏览器内置)
    • 处理中间证书缺失的情况

    解决方案是写了一个完整的证书链提取和验证模块,包括:

    • 从 TLS 连接提取完整证书链
    • 验证每个证书的签名和有效期
    • 检测链断裂和不完整的情况
    • 树形结构可视化展示

    2. 安全评分系统的设计

    为了让用户快速了解证书的安全状况,做了一个 A+ 到 F 的评分系统。核心逻辑:

    四个维度加权评分 - 证书有效性:30% - 链完整性:25% - 加密强度:25% - 协议版本:20% 如果有严重问题(如证书过期),评级上限为 C 

    难点在于:

    • 权重分配如何合理
    • 扣分规则如何设计
    • 如何给出有价值的改进建议

    最终采用了分层评分,每个维度独立计算,再加权汇总。

    guardssl

    3. 多语言路由的 Hydration 问题

    支持 6 种语言时遇到了 React Hydration 错误:

    // 错误做法 // app/[locale]/layout.tsx 中包含 <html> 标签 // 与根 layout 冲突 // 正确做法 // 根 layout 只有一个 <html> 标签 // 使用客户端组件动态更新 lang 属性 

    4. Redis 缓存的降级处理

    为了提升认证性能,加了 Redis 缓存。但需要考虑:

    • Redis 不可用时怎么办?
    • 缓存和数据库数据不一致怎么办?

    解决方案:

    • Redis 连接失败自动降级到数据库
    • 数据库更新时主动失效缓存
    • 提供缓存统计 API 监控命中率

    5. PageSpeed 优化

    最初 Lighthouse 跑分只有 60 多分,主要问题:

    Javascript Bundle 太大

    • 使用 Next.js 的动态导入( dynamic import )按需加载组件
    • 移除未使用的依赖
    • 启用 Tree Shaking

    图片优化

    • 使用 Next.js Image 组件自动优化
    • 添加合适的 placeholder
    • 启用图片懒加载

    字体加载

    • 使用 next/font 自动优化字体
    • 减少字体变体数量
    • 使用 font-display: swap 避免布局偏移

    关键渲染路径

    • 识别关键 CSS ,内联到 HTML
    • 延迟加载非关键 Javascript
    • 优化第三方脚本加载顺序

    第三方脚本优化

    • Google Analytics 、Crisp Chat 等延迟加载
    • 使用 defer/async 属性
    • 考虑使用 Web Workers 处理耗时任务

    最终优化后:

    • Performance: 60 → 95
    • Accessibility: 85 → 98
    • Best Practices: 90 → 100
    • SEO: 100

    一些技术亮点

    证书链可视化

    用树形结构展示证书链,支持展开/折叠,不同状态用颜色编码:

    • 绿色:有效
    • 黄色:即将过期
    • 红色:已过期

    安全问题检测

    自动检测不安全的加密算法:

    • MD5 、SHA-1 签名算法
    • RC4 、DES 等弱加密
    • TLS 1.0/1.1 等旧协议

    多渠道通知

    目前支持邮件、Slack 、Discord 、Telegram 、飞书五种通知渠道,用户可以自由组合。

    guardssl

    项目地址

    https://guardssl.info

    功能:

    • 免费 SSL 证书检查
    • 域名监控和过期提醒
    • 安全评分和改进建议
    • 多语言支持(中英日法西)

    欢迎试用和反馈,有什么问题可以一起交流。

    billzhuang
        1
    billzhuang  
       7 天前 via iPhone
    数据库做的 queue ?还是请求直接干过来
    yeahjw
        2
    yeahjw  
    OP
       7 天前
    @billzhuang redis+postgres ,定时监控逻辑单独走部署的另一套后端
    ttlive
        3
    ttlive  
       7 天前
    你可以参考一下 certd ,大部分大家所需求的功能都在上面。
    yeahjw
        4
    yeahjw  
    OP
       7 天前
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4132 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 04:09 PVG 12:09 LAX 20:09 JFK 23:09
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86