禁用密码修改需全链路阻断:移除前端路由、后端接口返回403、禁用框架自动配置、SSO场景忽略password字段、ORM层拦截赋值、关闭管理功能、删除邮件模板与API文档,并通过curl和日志验证。
禁用密码修改入口:从应用层 UI 到路由拦截
用户点不到、进不去,是最直接的禁用方式。重点不是“锁住密码字段”,而是让整个修改密码流程不可达。
-
/change-password、/account/security这类前端路由,必须从路由表中移除或加权限守卫——守卫逻辑里明确拒绝非管理员角色访问 - 后端对应接口如
PUT /api/v1/users/password必须返回403 Forbidden,不能只返回405 Method Not Allowed(后者容易被绕过) - 如果用的是现成框架(如 Spring Security),检查是否误启用了
DefaultPasswordChangeFilter或类似自动配置;禁用方式是显式排除该 filter,而非仅隐藏按钮
SSO 认证成功后,禁止向本地数据库写入或更新 password 字段
即使用户通过 SSO 登录成功,系统仍可能在首次同步时把空密码或占位符写进 users.password 字段——这会为后续密码重置埋雷。
- SSO 回调处理逻辑中,对
password字段做硬性忽略:入库前清空、设为NULL或固定值(如"sso_only"),且数据库该字段需设为NOT NULL DEFAULT 'sso_only' - ORM 层(如 Django 的
save()、Rails 的before_save)加钩子,拦截任何对password的赋值操作,直接抛异常或静默丢弃 - 特别注意 LDAP/AD 同步场景:
user.password字段绝不能映射 LDAP 的userPassword属性——LDAP 密码不可读,强行同步只会写入乱码或触发加密失败
禁用所有密码相关 API 和管理后台功能开关
很多系统留着“密码策略配置”“自助重置邮件模板”这类管理项,只要开着,就等于留了后门。
- 关闭管理后台中所有带
password_reset、force_change_password、password_policy字样的功能开关,不只是隐藏 UI,要真正停掉对应 controller action 和 cron job - 检查邮件服务配置:确保
reset_password_email_enabled配置项为false,且模板文件(如reset_password.html.erb)被物理删除或重命名,避免被路径猜测访问 - API 文档(如 Swagger)中,删掉所有
POST /api/password/reset、POST /api/password/change等路径定义——文档残留会误导开发和测试人员
验证禁用是否生效:别只测登录,要测“越权尝试”
真正有效的禁用,是连错误提示都不暴露系统能力。常见验证盲区是只测“正常用户登不进去”,却漏掉“攻击者发个 PUT 请求试试”。
- 手动用 curl 模拟请求:
curl -X PUT https://app.example.com/api/users/123 -H "Authorization: Bearer xxx" -d '{"password":"new123"}',确认返回403而非422 Unprocessable Entity(后者说明字段校验仍运行) - 检查日志:所有密码相关 endpoint 的访问记录应极少(理想为零),若发现大量
403日志,说明前端没拦住,得回溯路由和鉴权链路 - 最易忽略的一点:数据库连接池、运维脚本、数据迁移工具是否还保留着
UPDATE users SET password = ...这类 SQL?这些地方一旦执行,就彻底绕过所有应用层控制











