新功能解读系列文章(5):DSN 密文保护——连接串密码不再明文裸奔
gt-checksum v4.0.0 新功能解读系列文章5DSN 密文保护——连接串密码不再明文裸奔在数据库校验和修复工具中连接串几乎是最敏感的配置之一。过去为了使用方便很多配置文件会直接写入数据库明文密码。gt-checksum v4.0.0 起srcDSN/dstDSN中的 password 必须使用ENC[...]密文并新增独立工具gt-dsn-crypt生成 32 字节 base64 key 与 AES-256-GCM 密文让连接串密码保护从“建议项”变成“强约束”。一、功能简介v4.0.0 新增连接串密码加密能力核心变化可以概括为三点能力说明ENC[...]密文格式srcDSN/dstDSN中的 password 必须使用ENC[...]密文gt-dsn-crypt工具独立生成 key、加密 password、解密校验密文统一日志脱敏gt-checksum、repairDB、连接池日志均不会完整输出明文 password 或密文新增工具gt-dsn-cryptgt-dsn-crypt提供三个子命令子命令作用gen-key生成 32 字节随机 key并以 base64 输出encrypt使用 key 将明文 password 加密为ENC[...]密文decrypt使用 key 解密ENC[...]用于校验密文是否正确典型使用方式# 1. 生成 32 字节 base64 keyKEY$(gt-dsn-crypt gen-key)# 2. 推荐从文件读取 password避免明文进入 shell historyprintf %s 数据库密码 ./password.txt# 3. 生成 ENC[...] 密文GT_CHECKSUM_DSN_KEY$KEY gt-dsn-crypt encrypt --password-file ./password.txt# 4. 启动 gt-checksum 时提供同一个 keyGT_CHECKSUM_DSN_KEY$KEY gt-checksum -c ./gc.conf配置文件中的 DSN 变为srcDSNmysql|user:ENC[v1:aes256gcm:default:...:...]tcp(src-host:3306)/information_schema?charsetutf8mb4dstDSNmysql|user:ENC[v1:aes256gcm:default:...:...]tcp(dst-host:3306)/information_schema?charsetutf8mb4二、功能作用及使用场景深入解读2.1 为什么要强制加密 DSN password在生产环境中明文数据库密码的风险远比想象中更常见场景一配置文件泄露gc.conf通常会被放在运维目录、部署目录或自动化平台中。一旦目录权限配置不当明文数据库密码就可能被非授权用户读取。场景二日志与报错泄露工具启动失败、参数校验失败、连接池初始化失败时如果直接打印 DSN明文 password 可能进入终端日志、CI 日志、工单截图或监控采集系统。场景三多人协作与审计迁移项目通常涉及 DBA、研发、运维、测试多角色协作。配置文件被多人传递时明文密码会在聊天工具、邮件、文档中扩散后续很难追踪和回收。场景四临时文件与历史命令残留即使最终配置文件被删除明文密码仍可能残留在 shell history、备份文件、编辑器 swap 文件中。加密后即使密文泄露没有 key 也无法直接还原 password。因此v4.0.0 不再只是“建议不要写明文密码”而是在启动阶段直接校验DSN password 不是ENC[...]程序 fail-fast 退出。2.2ENC[...]密文格式是什么v4.0.0 使用统一的密文格式ENC[v1:aes256gcm:kid:nonce_b64url:ciphertext_b64url]各字段含义如下字段说明v1密文格式版本aes256gcm加密算法AES-256-GCMkey id默认default为后续密钥轮换预留随机 nonce使用 base64 URL-safe 编码密文和认证标签使用 base64 URL-safe 编码示例ENC[v1:aes256gcm:default:REPLACE_NONCE:REPLACE_CIPHERTEXT]需要注意的是只加密 password 片段不会加密 host、port、库名、charset、SSL 参数等连接配置信息。例如# 加密前v4.0.0 起不再支持srcDSNmysql|user:plain_passwordtcp(src-host:3306)/information_schema?charsetutf8mb4# 加密后srcDSNmysql|user:ENC[v1:aes256gcm:default:...:...]tcp(src-host:3306)/information_schema?charsetutf8mb4这种设计兼顾了安全性和可运维性密码被保护起来但连接目标、库名和参数仍然可见便于排查配置问题。2.3 AES-256-GCM同时保证保密性和完整性gt-dsn-crypt使用 Go 标准库中的 AES-GCM 实现block, _ : aes.NewCipher(key)gcm, _ : cipher.NewGCM(block)nonce : make([]byte, gcm.NonceSize())rand.Read(nonce)ciphertext : gcm.Seal(nil, nonce, []byte(password), nil)这里有几个关键点key 必须是 32 字节对应 AES-256。每次加密都会生成随机 nonce同一个 password 用同一个 key 加密两次也会得到不同的ENC[...]密文。GCM 自带认证标签解密时会校验密文是否被篡改。如果 key 错误或密文被修改会返回解密失败而不是输出错误的 password。这意味着ENC[...]不只是“混淆字符串”而是具备认证加密能力的密文格式。2.4 key 从哪里来v4.0.0 的 key 管理遵循两个原则不内置默认 key不从配置文件读取 key。key 来源只有两种来源优先级说明--key最高命令行参数覆盖环境变量GT_CHECKSUM_DSN_KEY次高未指定--key时读取该环境变量示例# 使用环境变量GT_CHECKSUM_DSN_KEY$KEY gt-checksum -c ./gc.conf# 使用 --key 覆盖环境变量gt-checksum -c ./gc.conf --key $KEYrepairDB 和 gt-dsn-crypt 也使用同样的 key 机制# repairDB 使用环境变量GT_CHECKSUM_DSN_KEY$KEY repairDB -conf ./gc.conf ./fixsql# repairDB 使用 --keyrepairDB -conf ./gc.conf --key $KEY ./fixsql# gt-dsn-crypt encrypt 使用 --keygt-dsn-crypt encrypt --key $KEY --password-file ./password.txtv4.0.0不支持密钥文件也不支持把 key 写在gc.conf中。这是为了避免“密码加密了但解密 key 又和配置文件放在一起”的伪安全。2.5 启动阶段 fail-fast明文密码直接拒绝gt-checksum 在读取配置时会立即解析srcDSN/dstDSN并调用统一的连接串解析逻辑要求连接串中必须使用密文。因此password 是ENC[...]加载 key 并解密password 是明文直接报错退出