# 修管理后台登录 2FA 设备验证失效 (P0 安全降级) **日期**: 2026-05-06 **类型**: fix (P0 安全降级,后端配置默认值修复,无前端影响) **PR**: wx/HL #1699 (已合并 dev,等运维/用户合 main 部署正式) **关联工单**: #1698 **引入**: 2026-04-03 PR #144 (commit 538635e) ## 问题 切换电脑/浏览器登录管理后台,**应该**触发企业微信扫码 2 次验证 (设备指纹+企微 2FA);**实际**任何账号(不只内置 admin)直接账号密码即可登录,2FA 完全失效。 影响 dev/test/prod 全环境近一个月。 ## 根因 `hl-user-service/src/main/resources/application.yml:69-70`: ```yaml auth: 2fa: enabled: false # ← 默认关 ``` `AdminAuthService.java:155` 跳过判断: ```java if ("admin".equals(admin.getUsername()) || !twoFactorEnabled) { // 直接发 token,跳过设备指纹比对+企微 2FA 流程 } ``` `!twoFactorEnabled` = `!false` = `true` → 任何账号都跳过。 Nacos dev/test/prod 三套 `hl-user-service-{env}.yml` 均**未覆写** `auth.2fa.enabled`,全部吃 application.yml 默认值。 ## 引入溯源 PR #144 (2026-04-03 commit `538635e`) "代码安全审计修复(8项)": > CRITICAL: 2FA跳过改为显式配置(auth.2fa.enabled),移除环境名判断 意图把"用环境名判 dev 跳过"换成"用配置开关",**默认值意外写反** —— 安全修复想让默认 ON,实际写成 OFF。 ## 修复 | 文件 | 改动 | |------|------| | `hl-user-service/src/main/resources/application.yml` | `enabled: false → true` + 注释说明 | | `nacos-config/hl-user-service-dev.yml` | 显式覆写 `auth.2fa.enabled: true` 防回归 | | `hl-user-service/.../config/Auth2faDefaultEnabledAuditTest.java` | 新增守护单测,防 PR #144 类反转再发 | 内置 `admin` 账号在 line 155 第一条件 `"admin".equals(username)` 不变,仍跳过 2FA 避免 super-admin 锁死。 ## 影响范围 - **受波及账号**: 所有非内置 admin 的管理员 (即所有真实业务账号) - **数据污染**: 无 (仅认证流程降级,未污染数据) - **回滚**: `git revert` 1 commit ## 验证 ### 单测 - `mvn test -Dtest=AdminAuthServiceTest` → 58/58 全绿 (含已有的 `login_untrustedDevice_requires2FA` / `login_trustedDevice_issuesToken` / `login_superAdmin_skips2FA_issuesTokenDirectly`) - `mvn test -Dtest=Auth2faDefaultEnabledAuditTest` → 1/1 (反向验证: 改回 false 立即报 `expected: but was: `) ### 测试服 round-trip (dev 部署后) ```bash # 期望 1: 非 admin 账号新设备登录 → requireTwoFa=true && token=null curl -k -X POST 'https://api.test.1814.love:9443/admin/auth/login' \ -H 'Content-Type: application/json' \ -H 'X-Device-Fingerprint: NEW_DEVICE_TEST' \ -d '{"username":"<非admin账号>","password":"<密码>"}' # 期望: {"code":"200","data":{"requireTwoFa":true,"token":null,...}} # 期望 2: 内置 admin 仍跳过 2FA curl -k -X POST 'https://api.test.1814.love:9443/admin/auth/login' \ -H 'Content-Type: application/json' \ -d '{"username":"admin","password":"Admin@123456"}' # 期望: {"code":"200","data":{"token":"eyJ...",...}} (token 直接发) # 期望 3: 已信任设备直发 token (admin_device.is_trusted=true) # 期望 4: 换浏览器 (不同 fingerprint) → admin_device 不命中 → requireTwoFa=true ``` ## 部署计划 - ✅ dev 测试服: 自动部署 (PR 合并触发) - ⏳ prod: 用户手动合 dev → main 后,运维/管理员通过 [Deploy Panel](https://dep.test.1814.love:9443) 触发 hl-user-service prod 部署。**仅 application.yml 改动,nacos prod 无需推送**(prod nacos 未覆写,jar 内默认值 true 立即生效)。 - 如需 prod nacos 也加显式覆写防回归,在 `正式环境Nacos配置/hl-user-service-prod.yml` 已落本地参考,运维同步推 nacos prod 即可。 ## 经验沉淀 落 `memory/experience/backend-dev/yml-default-value-must-be-secure-by-default.md` — **配置默认值反转规则**: 任何"启用/禁用"类配置 (`enabled`/`required`/`strict`/`validate`),默认值必须取**安全/严格**那一侧: - `auth.2fa.enabled` 默认 `true` (开启) - `validate-on-migrate` 默认 `true` (校验) - `strict-mode` 默认 `true` (严格) - `cors.allow-all-origins` 默认 `false` (拒绝) 把不安全/松散值留给 nacos 显式覆写,**绝不让 application.yml 默认值成为安全降级源**。 防回归手段: 给关键 `enabled: true` 配置写 `*DefaultEnabledAuditTest` 守护测试,任何回退立即编译期/单测期阻断。 ## 通知 - 后端独立修复,无前端改动需求 (mmg/yst 不用动) - 用户/运维: 部署 prod 后请告知,以便 round-trip 4 个验证场景闭环 + 关闭工单 #1698