Loading... # httpscheck SSL/TLS 证书检查工具设计 # 一、背景与目标 ## 1. 项目背景 ### A. 业务场景 SSL/TLS 证书是现代互联网安全的基石。证书管理不善会导致服务中断、安全漏洞等问题。系统管理员和开发人员需要一个可靠的工具来检查 HTTPS 证书的有效性、信任链状态和系统配置。 ### B. 痛点分析 - OpenSSL 命令复杂,输出难以解析 - 缺少中文友好的检查工具 - 需要验证证书在系统中的实际信任状态 - 跨平台检查工具匮乏 ## 2. 设计目标 ### A. 功能目标 - 完整的证书链验证 - 证书有效期检查(过期、即将过期、有效) - 系统 CA 证书路径测试 - 彩色终端输出 ### B. 非功能目标 - 跨平台支持(Linux、macOS、Windows) - 纯 Go 实现,无外部 OpenSSL 依赖 - 静态编译,单文件部署 - 高性能,支持超时控制 # 二、总体设计 ## 1. 设计原则 - **单一职责**:每个包职责明确 - **依赖倒置**:通过共享类型打破循环依赖 - **接口隔离**:CLI 层与业务逻辑分离 - **开闭原则**:易于扩展新的检查功能 ## 2. 系统架构 ```mermaid graph TB User[用户] --> CLI[CLI 层 cmd/] CLI --> Root[root.go 根命令] Root --> Chains[chains.go 证书链检查] Root --> CACert[cacert.go CA 路径测试] Root --> Output[output.go 简单输出] Chains --> Checker[pkg/checker/] CACert --> Checker Output --> Checker Checker --> CertUtil[pkg/certutil/] Checker --> Types[pkg/types/] CertUtil --> Types Checker --> Logger[pkg/logger/] Logger --> Stdout[(标准输出)] ```  ## 3. 模块说明 | 模块 | 文件 | 职责 | |------|------|------| | CLI 层 | cmd/*.go | 命令行解析、参数处理、用户交互 | | 检查器 | pkg/checker/chains.go | 证书链获取、验证、系统信任检查 | | 证书工具 | pkg/certutil/*.go | 证书解析、格式化、系统 CA 路径 | | 类型定义 | pkg/types/types.go | 共享数据结构、枚举常量 | | 日志系统 | pkg/logger/logger.go | 彩色输出、日志级别控制 | ## 4. 数据流 ```mermaid sequenceDiagram participant U as 用户 participant C as CLI 层 participant K as Checker participant P as CertUtil participant L as Logger U->>C: 执行命令 C->>K: CheckChain() K->>K: retrieveCertificates() Note over K: 建立 TLS 连接<br/>获取证书链 K->>P: ParseCertificate() Note over P: 解析证书信息<br/>计算指纹<br/>判断状态 P-->>K: CertificateInfo K->>K: verifyChain() Note over K: 验证证书链<br/>检查系统信任 K-->>C: ChainCheckResult C->>P: FormatTable() P-->>C: 格式化字符串 C->>L: 输出 L-->>U: 彩色结果 ```  # 三、核心模块设计 ## 1. 类型系统 ### A. 证书类型判断 ```go type CertType string const ( CertTypeServer CertType = "服务器证书" CertTypeIntermediate CertType = "中间证书" CertTypeRoot CertType = "根证书" ) ``` **判断逻辑**: - 服务器证书:链中的第一个证书 - 根证书:链中最后一个且自签名 - 中间证书:介于两者之间 ### B. 证书状态判断 ```go type CertStatus string const ( CertStatusValid CertStatus = "有效" CertStatusExpired CertStatus = "已过期" CertStatusExpiring CertStatus = "即将过期" // < 30天 ) ``` **阈值设定**:30 天作为即将过期的警告阈值 ### C. 核心数据结构 ```go type CertificateInfo struct { Index int Type CertType Subject pkix.Name SubjectStr string Issuer pkix.Name IssuerStr string NotBefore time.Time NotAfter time.Time DaysRemaining int SerialNumber string Fingerprints map[string]string PublicKeyInfo PublicKeyInfo SignatureAlg string Status CertStatus } ``` ## 2. 证书链检查 ### A. 获取证书链 ```mermaid graph TD A[开始] --> B[创建 Dialer] B --> C[配置 TLS Config] C --> D[建立 TCP 连接] D --> E{连接成功?} E -->|否| F[返回错误] E -->|是| G[执行 TLS 握手] G --> H{握手成功?} H -->|否| F H -->|是| I[提取 PeerCertificates] I --> J[返回证书链和连接] ```  **关键代码**: ```go func retrieveCertificates(ctx context.Context, domain string, port int, timeout time.Duration) ([]*x509.Certificate, *tls.Conn, error) { dialer := &net.Dialer{Timeout: timeout} conn, err := tls.DialWithDialer(dialer, "tcp", fmt.Sprintf("%s:%d", domain, port), &tls.Config{ ServerName: domain, InsecureSkipVerify: true, // 获取证书但不验证 }) if err != nil { return nil, nil, err } state := conn.ConnectionState() return state.PeerCertificates, conn, nil } ``` ### B. 验证证书链 ```mermaid graph TD A[开始] --> B[获取系统 CA 池] B --> C[创建中间证书池] C --> D[添加非服务器证书到中间池] D --> E[配置验证选项] E --> F[调用 Verify 方法] F --> G{验证成功?} G -->|是| H[返回 true] G -->|否| I[返回错误] ```  **验证策略**: - 使用系统 CA 证书池作为信任根 - 将除服务器证书外的所有证书加入中间证书池 - 验证第一个证书(服务器证书)的完整链 ### C. 系统信任检查 ```mermaid graph LR A[根证书] --> B{遍历系统证书池} B --> C[解析 DER 证书] C --> D{主题匹配?} D -->|是| E[比较 SubjectKeyId] D -->|否| B E --> F{公钥匹配?} F -->|是| G[找到匹配] F -->|否| B ```  **匹配策略**:先比较主题字符串,再比较 SubjectKeyId 确保公钥一致 ## 3. 证书解析 ### A. 公钥信息提取 支持三种公钥类型: | 类型 | 算法标识 | 密钥长度获取 | |------|---------|-------------| | RSA | RSA | N.BitLen() | | ECDSA | ECDSA | Curve.Params().BitSize | | Ed25519 | Ed25519 | 固定 256 | ### B. 指纹计算 ```go func GetFingerprints(cert *x509.Certificate) map[string]string { fingerprints := make(map[string]string) sha256Hash := sha256.Sum256(cert.Raw) fingerprints["SHA256"] = hex.EncodeToString(sha256Hash[:]) sha1Hash := sha1.Sum256(cert.Raw) fingerprints["SHA1"] = hex.EncodeToString(sha1Hash[:]) return fingerprints } ``` ### C. 状态判断 ```go func DetermineCertStatus(notAfter time.Time) types.CertStatus { daysRemaining := CalculateDaysRemaining(notAfter) if daysRemaining < 0 { return types.CertStatusExpired } if daysRemaining < 30 { return types.CertStatusExpiring } return types.CertStatusValid } ``` # 四、跨平台支持 ## 1. 平台检测 ```go func GetPlatformCAPaths() []string { switch runtime.GOOS { case "linux": return getLinuxCAPaths() case "darwin": return getMacOSCAPaths() case "windows": return getWindowsCAPaths() default: return []string{} } } ``` ## 2. CA 证书路径 ### A. Linux 平台 | 发行版 | 路径 | |--------|------| | Debian/Ubuntu | /etc/ssl/certs/ca-certificates.crt | | RedHat/CentOS | /etc/pki/tls/certs/ca-bundle.crt | | Arch Linux | /etc/ssl/certs/ca-bundle.crt | | 通用目录 | /etc/ssl/certs | ### B. macOS 平台 | 路径 | |------| | /etc/ssl/cert.pem | | /usr/local/etc/openssl/cert.pem | ### C. Windows 平台 使用 Windows 证书存储,无需文件路径 ## 3. 颜色输出 ```go func detectColorSupport() bool { // 检查是否为终端设备 if fileInfo, _ := os.Stdout.Stat(); (fileInfo.Mode() & os.ModeCharDevice) == 0 { return false } // Windows 特殊处理 if runtime.GOOS == "windows" { return os.Getenv("WT_SESSION") != "" || os.Getenv("ConEmuANSI") == "ON" || os.Getenv("ANSICON") != "" } return true } ``` # 五、构建与部署 ## 1. 跨平台编译 ```mermaid graph LR A[源码] --> B[go build] B --> C{CGO_ENABLED?} C -->|0| D[静态编译] C -->|1| E[动态链接] D --> F[单一可执行文件] E --> F F --> G[不同平台目标] ```  ## 2. 支持平台 | 操作系统 | 架构 | 输出文件 | |---------|------|---------| | Linux | amd64 | httpscheck-linux-amd64 | | Linux | arm64 | httpscheck-linux-arm64 | | macOS | amd64 | httpscheck-darwin-amd64 | | macOS | arm64 | httpscheck-darwin-arm64 | | Windows | amd64 | httpscheck-windows-amd64.exe | | Windows | arm64 | httpscheck-windows-arm64.exe | ## 3. 版本信息注入 ```bash VERSION="1.0.0" BUILD_TIME=$(date +%Y-%m-%d-%H:%M:%S) ldflags="-s -w" ldflags="${ldflags} -X 'main.version=${VERSION}'" ldflags="${ldflags} -X 'main.buildTime=${BUILD_TIME}'" go build -ldflags "${ldflags}" -o httpscheck . ``` # 六、使用示例 ## 1. 默认模式(完整检查) ```bash ./httpscheck example.com ``` 依次执行:cacert 检查 → chains 验证 → output 输出 ## 2. 证书链检查 ```bash ./httpscheck chains -p 443 -t 10 -v example.com ``` ## 3. CA 路径测试 ```bash ./httpscheck cacert --all-paths example.com ``` ## 4. 简单输出 ```bash ./httpscheck output --full example.com ``` # 七、设计亮点 ## 1. 纯 Go 实现 - 无外部 OpenSSL 依赖 - 使用 crypto/tls 和 crypto/x509 标准库 - 跨平台编译简单 ## 2. 分层架构 通过 pkg/types 打破循环依赖: ```mermaid graph LR A[checker] --> D[types] B[certutil] --> D C[logger] --> D ```  ## 3. 用户体验 - 中文界面 - 彩色输出 - 状态图标(有效/过期/即将过期) - 详细错误信息 ## 4. 高性能 - 支持超时控制 - context 传递 - 连接复用 # 八、未来改进 ## 1. 功能扩展 - JSON 输出格式 - 并发检查多个域名 - 证书监控告警 - 证书自动续期提醒 ## 2. 质量提升 - 单元测试覆盖 - 基准测试 - 集成测试 ## 3. 工程化 - CI/CD 流水线 - 自动化发布 - Homebrew 安装支持 *** ## 参考资料 1. [Go crypto/x509 包文档](https://pkg.go.dev/crypto/x509) 2. [Go crypto/tls 包文档](https://pkg.go.dev/crypto/tls) 3. [Cobra CLI 框架](https://github.com/spf13/cobra) 4. [项目源码仓库](https://github.com/yourusername/httpscheck) 最后修改:2026 年 02 月 02 日 © 允许规范转载 赞 如果觉得我的文章对你有用,请随意赞赏