密钥轮换清单.md 11.3 KB

密钥轮换清单(老仓库 zteits-clouds 明文凭据)

用途:老仓库把 75 个 application*.properties 的凭据写成了明文(零 jasypt 加密), 其中相当一部分是生产环境的。这份清单是「需要去各控制台改哪些口令」的工作单。

本次不改老仓库任何代码(老工程仍在跑)。新工程 parking-cloud 已全程走环境变量, 不继承这些值;轮换是为了堵住"已经泄露"这件事本身。

统计口径:扫老仓库全部 application*.properties,取未注释的 druid.password / spring.redis.password / spring.rocketmq.accessKey|secretKey / irain.appsecret / spring.mail.password / telecom.iot.secret。 本文件不含任何口令值。

⚠️ 该口径只覆盖 properties。另外还有一批凭据写在 YAML 与 Java 源码里 (企业微信、微信支付 v3、微信证书口令),properties 扫描根本扫不到, 见 §5。§1 的数量统计不含 §5 那批。

1. 摘要

项目 数量
含明文凭据的配置文件 75
数据库口令 34
Redis 口令 75
RocketMQ accessKey/secretKey 22 / 22
irain.appsecret(第三方对接) 23
spring.mail.password(163 个人邮箱) 6
telecom.iot.secret(电信 IoT) 4

上表之外还有 4 类(企业微信 4 个应用的 secret/token/aesKey、微信支付 v3 的 4 个值 + 3 个证书路径、微信证书口令 ×2、支付宝 alipay.partner ×3、wx.cert.pass ×3、 telecom.iot.appid ×4),见 §5。

2. 优先级

级别 对象 为什么
🔴 P0 生产 RDS 全部账号、47.96.41.38 公网库、内网 root 账号、163 邮箱口令 生产数据 + 公网可达 + 个人账号,泄露即等于失控
🟠 P1 测试/开发 RDS 账号、Redis、RocketMQ AK/SK、irain.appsecret、电信 IoT secret 测试库常与生产同结构、同数据;第三方密钥可被冒用产生费用
🟡 P2 内网固定 IP 上的库账号 仅在办公网可达,风险相对低,但仍是弱口令重灾区

3. 数据库口令

3.1 生产

实例 库 账号 出现在
rm-2zeq6z9f00w52tcq7jo.mysql.rds.aliyuncs.com zt_sys zt_park zt_pay zt_order zt_bill zt_business tsys tpark tpay torder tbill tbusiness 各模块 application.properties / -prod.properties
同上 zt_park zt_pay 18911425167@163.com ← 用个人邮箱当库账号 zteits-park、zteits-pay
rm-do28s6ftpr01f14b0yo.mysql.zhangbei.rds.aliyuncs.com zt_bill bill zteits-bill/application.properties
rm-uf6wj7qw3f31kz69wzo.mysql.rds.aliyuncs.com zt_park(丹阳) park zteits-park/application-danyang.properties
10.117.185.28 zt_sys sys zteits-customer-service/application-prod.properties

3.2 公网暴露 🔴

实例 库 账号 出现在
47.96.41.38:3306(公网 IP) zt_order order zteits-pay/application-test47.properties

名字叫 -test47,但从公网可达且账号是 order——必须确认它到底连的是哪套数据,再决定轮换还是关停端口。

3.3 内网固定 IP(含 root!)

实例 库 账号 出现在
192.168.1.167:3306 zteits-zf zteits-sys-bak zteits-park root zteits-bill zteits-pay zteits-sys zteits-park 的 -test195.properties
192.168.129.139:3306 zteits-zf zteits-sys zteits zteits-pay zteits-sys 的 -test61.properties
10.112.92.89:3306 zt_sys zt_order zt_park sys order park 各模块 -wwwtown.properties

用 root 连业务库(4 个文件)是这套配置里最该先改的一条。

3.4 测试 / 开发

实例 库 账号
renniting-test-net.mysql.zhangbei.rds.aliyuncs.com zt_park zt_sys zt_order_n park tsys torder
renniting-dev-net.mysql.zhangbei.rds.aliyuncs.com dev_charge dev_park dev_order_n zteits_dev
192.168.1.167 zteits-zf root(同 §3.3)

4. 非数据库凭据

凭据 数量 说明
spring.redis.password 75 按环境各不相同;逐个环境轮换,别只改生产
spring.rocketmq.accessKey / secretKey 22 / 22 阿里云 AK/SK 成对,一次轮换要同步改所有引用方,漏一个就消息不通
irain.appsecret 23 第三方(爱瑞恩)对接密钥,需找对方重新签发,不是自己改
telecom.iot.secret 4 中国电信 IoT 平台,同样需对方重签
spring.mail.password 6 是个人的 163 邮箱口令(账号 18911425167@163.com),且出现在 zteits-park / zteits-pay 的生产配置里。请优先改成专用发信账号 + 授权码,别用个人邮箱主密码

5. 硬编码在 YAML / Java 源码里的凭据(不在 §1 口径内)

这一批是properties 扫描扫不到的:要么写在 .yml,要么直接写死在 Java 源码里。 它们同样已经进过 git,同样算泄露。

5.1 企业微信(zteits-wxcp-portal/src/main/resources/application.yml)

项 值形态 说明
wechat.cp.corpId 明文 企业 ID(ww...)
wechat.cp.appConfigs[].agentId 明文 4 个:1000002 1000003 1000004 1000005(不敏感,是标识)
wechat.cp.appConfigs[].secret 明文 ×4 应用 Secret,泄露即可用企业身份发消息
wechat.cp.appConfigs[].token 明文 ×4 回调 Token
wechat.cp.appConfigs[].aesKey 明文 ×4 回调消息加解密 Key(EncodingAESKey)

该文件里还有整段被注释掉的另一套环境(agentId 1000002~1000006 的 secret/token/aesKey), 注释不改变"已经提交过"的事实,一并去企业微信后台重置。 轮换入口:企业微信管理后台 → 应用 → 每个自建应用 → 「Secret」重置 / 「接收消息」重新生成 Token 与 EncodingAESKey。 ⚠️ secret 一旦重置,正在跑的老 zteits-wxcp-portal(18031)会立刻发不出告警, 需按 §6 的顺序(先配新值再停旧值)操作。

新工程对应配置:application.yaml 的 wechat.cp.*,环境变量名 WECHAT_CP_CORP_ID / WECHAT_CP_SECRET_<agentId> / WECHAT_CP_TOKEN_<agentId> / WECHAT_CP_AESKEY_<agentId>。 仓库里默认给的是 app-configs: [] 空列表(能启动、不告警),真实值只在部署环境注入。

5.2 微信支付 v3(zteits-framework/.../com/clouds/common/utils/wx/Wechatpayapiv3Config.java)

写死在 Java 的 public static String 字段里(连 final 都没有,任何地方都能改):

字段 说明
appId 商户 AppID
merchantId 商户号
merchantSerialNumber 商户 API 证书序列号
apiV3key APIv3 密钥——最要命的一个,它能解密回调和平台证书
privateKeyPath / privateKeyName 商户私钥路径与文件名
wechatPayCertificatePath 平台证书路径
wechatv3CallBack 回调域名

轮换:微信支付商户平台 → 账户中心 → API 安全 → 重置 APIv3 密钥(同时重新申请 API 证书、更新序列号)。 重置 APIv3 密钥会让所有用到它的服务立刻失败(支付回调验签、退款、企业付款), 必须与 §6 的"先新后旧"一起排窗口。 新工程的做法:这些值不允许再出现在 Java 里,一律走环境变量(新工程本轮尚未改造该类, 该类是原样搬迁进 parking-legacy-common 的;改造时按同名环境变量注入)。

5.3 微信证书口令(两处,内容是同一份复制)

文件 字段
zteits-framework/src/main/java/com/clouds/common/entity/WeixinConfigure.java certPassword
zteits-order/src/main/java/com/zteits/order/util/WeixinConfigure.java certPassword

是微信支付 apiclient_cert.p12 的导出/读取口令。轮换 = 在商户平台重签 API 证书, 同时换 p12 口令,并同时改这两处(漏一处就会有一个模块用旧证书)。

5.4 properties 里遗漏统计的 3 个键

键 文件数 位置 说明
telecom.iot.appid 4 zteits-park 的 default / prod / test47 / danyang telecom.iot.secret 的配对方(secret 已在 §4 统计),轮换时成对
alipay.partner 3 zteits-order 的 default / prod / dev 支付宝商户 PID,与配套的私钥/公钥一起换
wx.cert.pass 3 zteits-order 的 default / prod / dev 微信支付证书口令(与 §5.3 的 certPassword 是同一类东西的两处写法)

5.5 新工程如何不再继承(已落地)

  • 类文件级别的硬编码(§5.2 / §5.3):本轮只做了原样搬迁,尚未改成环境变量 —— 属 P2/P3 的改造项,记在这里以免漏掉
  • spring.mail:新工程已在 application.yaml 用 SPRING_MAIL_HOST / SPRING_MAIL_PORT / SPRING_MAIL_USERNAME / SPRING_MAIL_PASSWORD 占位, 默认 username/password 为空(能启动、发信时报错,不静默)
  • wechat.cp:见 §5.1,默认空列表

6. 轮换顺序(避免把自己搞停)

  1. 先建新凭据、再用新凭据、最后才吊销旧的——直接改口令会让老工程当场连不上
  2. 数据库:CREATE USER 建新账号 → 授权 → 老工程配置改指新账号 → 观察 ✓ → 删旧账号
    • 不要用 root:新账号按库授最小权限(业务账号只需该库的 SELECT/INSERT/UPDATE/DELETE)
  3. RocketMQ / Redis:先改成"新旧都认"(Redis 用 requirepass 双读不成立,需安排停机窗口;RocketMQ AK/SK 可先加新 AK 再切)
  4. 第三方(irain / 电信 IoT):先发邮件找对方重签,这条链路最长,第一天就该发起
  5. 邮箱:申请专用发信账号 → 改 spring.mail.* → 观察 → 停用个人邮箱授权码

7. 轮换之后:确保新工程不再继承

新工程 parking-cloud 的约定(已落地,见 parking-cloud/CLAUDE.md):

  • 配置文件里只能出现 ${DB_PASSWORD:} 这类环境变量占位,真实值永不入库
  • 本地开发用 parking-cloud/私密/ 放凭据,该目录已在 .gitignore
  • 政务侧原本用 jasypt ENC(...) 的字段,并入后一律降级为环境变量,不再保留 jasypt

8. 本清单没有覆盖的

  • 百度地图 AK(5 个,硬编码在可视化大屏的 unit.js 与 HTML 里)——见重构方案 §5.6, 属于 P7 大屏重写范围,需要去百度控制台重新签发并作废旧 AK
  • 老仓库 git 历史里的凭据:改口令不能抹掉历史。若仓库要外发或转公开, 必须重写历史或直接重建仓库
  • 政务仓库 ZTEITS-PTMS 自身的明文凭据(本次只扫了 zteits-clouds)
  • Java 源码里的硬编码凭据只做了定点排查,不是全量扫描:§5.2 / §5.3 是拿 (private|public|static) …(Secret|ApiKey|apiV3key|passwd|password|accessKey|token) = "…" 这个模式在 8 个模块的 .java 上捞出来的(命中 3 个文件)。用别的写法藏起来的 (拼接、数组、Base64、System.getProperty 兜底)不在这次的命中里