# 密钥轮换清单(老仓库 `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_` / `WECHAT_CP_TOKEN_` / `WECHAT_CP_AESKEY_`。 > 仓库里默认给的是 **`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` 兜底)不在这次的命中里