技能|Web权限与验密守卫加固法
适用场景
家庭 / 小团队内部系统加权限,尤其是"共用一台设备、会切换账号"的场景。触发词:权限矩阵、越权、提权、切换账号验密、审计留痕、perms.py。
操作步骤
- 角色矩阵集中定义(单一可信源):
perms.py里
-ROLES = {'owner':..., 'life':..., 'guest':...},每角色含admin/delete/edit/add;
- 财务双入口同源:FINANCE_MODULES = {'finance','cw'},can()对这两个模块判据一致——否则业务(/txn记账流水 =finance)与台账(/l/cw=cw)一个可控、另一个裸奔;
-LIFE_WRITE={'finance','cw','op','zq'}(生活域可增改)、GUEST_ADD = ALL_MODULES - FINANCE_MODULES(子女仅可非财务新增)、ADMIN_MODULES={'audit','settings'}(仅户主)、LEDGER_MODULES=set(BY_KEY.keys())(十体系台账键复用,不重复维护)。 - 判权统一走
can(role, module, action):视图里只查self._can(module, action),散写if会让双入口不同源。 - 会话:
app.py的_make_session(name)用hmac.new(SECRET, payload, sha256)签名,payload =<姓名b64>|exp;Cookie 名hfms_sid(发往客户端Set-Cookie: hfms_sid=...; HttpOnly; SameSite=Lax,登出把 Max-Age 置 0);口令经db.verify_admin_password校验,不存明文。测试脚本别猜 Cookie 名。 - 切换账号必须验密(P0 守卫):
app._accounts_submit里先db.verify_admin_password(pw)通过才重发会话,否则返回"密码错误,切换账户失败"并中止;重发后再db.add_audit(..., 'switch', '切换账户')留痕。仅凭 Cookie 就能换账号 = 提权漏洞,这条是封口。 - 写操作埋点:所有增删改(导入/导出/备份还原)调
db.add_audit,字段含 时间/账号/角色/动作/对象(audit_log表)。 - 管理页后端二次判权:
/audit、/settings在ADMIN_MODULES中,can()对admin或ADMIN_MODULES一律只认 owner;前端隐藏按钮不算防护,后端_can('audit'/...)必须判。 - 围栏策略:网关未激活 = 全权限(本地自用);激活后未登录 = 只读成员(禁删、禁管理页);登录 = 全权且留痕。
- 验证:用低权限账号逐条访问高权限路由,期望全部被拒;再用"不验密直接带他人 Cookie"请求,期望仍被拦(P0 成立)。
注意边界
- 隐私红线:内部系统不暴露公网,异地访问走虚拟内网;证件号等仅显示后四位。
- 后端判权是唯一可信边界,前端隐藏只是体验;
can()是单一判据,别在前端再加一套。 - 审计表只追加,不给普通角色删改权限。
反例避雷
- 权限判定散写各处 → 双入口不同源,改一个漏一个。
- 只做前端隐藏 → 直接请求 URL 即可越权。
- 切换账号不验密 → 拿到设备即可提权(P0,必须封)。
- 口令明文/可逆存储 → 一旦泄露全盘失守。
- 测试脚本 Cookie 名写错(如写成 session)→ 满屏假 403,掩盖真实漏洞。
关联笔记
- [[技能|全页面回归冒烟法]]
- [[技能|吞噬异常统一留痕治理法]]
实战战绩
2026-09-28 首跑:把散落各处的判权收拢为 perms.py 的 ROLES/can();修掉财务双入口不同源(统一 FINANCE_MODULES);补上 app._accounts_submit 的切换验密守卫,封住 P0 提权;写操作全量 add_audit 埋点,管理页后端二次判权。低权限账号逐条访问高权限路由全部被拒。
版本记录
| 版本 | 日期 | 变更 |
|---|---|---|
| v1.0.0 | 2026-09-28 | 首版实战固化:矩阵集中→双入口同源→会话签名→切号验密→埋点→后端判权 |
| v1.1.0 | 2026-09-28 | 回填真实锚点:perms.py 各常量、can()、FINANCE_MODULES 同源、会话 hfms_sid/_make_session、_accounts_submit 验密、add_audit 留痕 |