第三十章 权限与安全

篇别:第六篇 数据安全

本章学习目标

  • 纵深防御 串联 ACL、记录规则、字段权限、Controller
  • 了解 敏感数据加密备份分工(应用层 vs 存储层)。
  • 配置 审计失败登录 的可观测性。
  • 落实 SQL 注入、CSRF、XSS 在 Odoo 自定义代码中的 检查点

导读:安全不是「装个 HTTPS」

Odoo 同时暴露 JSON-RPC、HTTP 路由、QWeb 报表、网站前端。一层疏漏(例如 Controller 手写 SQLcsrf=False 滥用t-raw)就可能 跨层放大。本章与 第七章ir.model.access / ir.rule 呼应,并补上 Web 与数据落盘 维度。


30.1 权限控制

30.1.1 知识要点

  • ACL(ir.model.access:模型级 CRUD;无读权限则 ORM 不可见(规则之前先过 ACL)。
  • 记录规则(ir.ruledomain_force 过滤行;global vs 组绑定;多规则 AND 组合。
  • 字段级groups= 在字段定义上;Odoo 19 字段访问相关能力见官方 Security 文档。
  • API 层check_accesshas_access_filtered_access 等(版本差异以文档为准)用于 显式校验
  • 顺序:可记 「认证用户 → ACL → Record Rules → 业务代码」sudo() 绕过规则,仅限受控内部逻辑

30.1.2 案例

口述画图题(练习用):从 /web/dataset/call_kwrecord.write,标出 session 用户 → env → check_access → rule SQL

30.1.3 截图占位

图 30-0 用户组与 ACL 列表

30.1.4 本节练习

  1. 案例:画出 「用户请求 → ACL → Rule → record」 判断顺序(可用列表或方框图)。
  2. 简答sudo()仍受 ACL 吗?(以你使用的版本行为为准,查阅后作答。)

参考答案提示:2. sudo() 典型为 超级用户上下文,通常 绕过规则;具体以源码 sudo 实现为准。


30.2 数据加密

30.2.1 知识要点

  • 传输HTTPS 终止于 反向代理HSTS证书轮换
  • 静态敏感字段:密码类用 哈希;对称密钥字段可用 fields.Char + 加密存储外部 KMS(自定义)。
  • 附件filestore 在磁盘;备份需 同时备份 DB + filestore
  • 数据库透明磁盘加密(TDE)卷加密应用层字段加密 互补,不是替代关系

30.2.2 案例

备份脚本检查清单pg_dump 时间戳filestore rsync恢复演练季度表

30.2.3 本节练习

  1. 简答filestore数据库备份 的加密策略各举 一条
  2. 判断:仅加密数据库文件即可保证 附件 不外泄。( )

参考答案提示:2. 错;附件可能在 filestore。


30.3 审计日志

30.3.1 知识要点

  • ir.logging:部分 错误与系统事件业务审计常需 自定义模型外部 SIEM
  • 登录:失败次数、来源 IP;与 fail2ban 等联动。
  • 数据变更mail.thread消息 可作为一种 业务级审计;高合规场景需 不可篡改链(外挂)。

30.3.2 案例

测试库 故意 输错密码,在 日志或设置 → 技术 中定位 失败记录(以部署为准)。

30.3.3 截图占位

图 30-1 ir.logging 或外部 SIEM 面板

30.3.4 本节练习

  1. 实操:在 测试环境 记录 一次失败登录日志行(打码敏感信息)。
  2. 简答业务审计表Web 服务器访问日志 各解决什么问题?

参考答案提示:2. 前者追踪 谁改了哪条业务记录;后者追踪 请求与会话层攻击面


30.4 SQL 注入防护(新增)

30.4.1 知识要点

  • 禁止 字符串拼接 用户输入 进 SQL。
  • 参数化cr.execute("... WHERE x = %s", (val,))
  • Odoo 19odoo.tools.SQL 组合片段时 遵循文档,避免 误判为已转义
  • ORM:优先 search;必须原生 SQL 时 白名单列名

30.4.2 案例

# 危险
# self.env.cr.execute("SELECT id FROM x WHERE name = '%s'" % name)

# 较安全
self.env.cr.execute("SELECT id FROM x WHERE name = %s", (name,))

30.4.3 本节练习

  1. 改错:找出项目中 一处 字符串拼接 SQL 并改为 参数化
  2. 简答:ORM 的 domain 来自 前端 时仍需注意什么?

参考答案提示:2. 恶意 domain / 字段名;应对 不可信输入白名单或服务端重建 domain


30.5 CSRF 与 XSS 防护(新增)

30.5.1 知识要点

  • CSRFtype='http'` 路由默认 校验 tokencsrf=False 仅用于 已签名 API、公开 webhook 等,并需 替代防护(签名、IP 限制)。
  • JSON-RPC:机制与 表单 POST 不同;查阅当前版本 文档 理解 会话与同源策略
  • XSS:QWeb t-esc 默认转义;t-out(新版本)按文档使用;避免 t-raw 处理用户 HTML,除非 消毒库 可控。

30.5.2 案例

from odoo import http

class MyController(http.Controller):
    @http.route("/my/ping", type="http", auth="public", website=True, csrf=False)
    def ping(self, **kw):
        # 必须有其它校验,例如 HMAC query token
        return request.make_json_response({"ok": True})

30.5.3 截图占位

图 30-2 Cookie 与 CSRF token(开发者工具)

30.5.4 本节练习

  1. 简答JSON-RPC表单 POSTCSRF 差异 一句话。
  2. 判断:所有 public 路由都应设 csrf=False 方便对接。( )

参考答案提示:2. 错。


本章综合练习

  1. 红队视角:攻击 自定义 Controller 的三条路径(SQL、越权、CSRF 各一)。
  2. 合规GDPR 删除请求 在 Odoo 中的处理要点(匿名化、备份、日志 各提一条)。
  3. 综合普通用户 在列表能看到 他人订单号打不开表单——可能是哪两类配置问题?
  4. 实操:用 测试用户 验证 ir.rule domain 与 groups 组合是否符合产品说明。

本章对应白皮书目录:第三十章 权限与安全。