概述
owner_id 是行级属主的锚点(OWD 行级作用域据此判定 update/delete 是否属主)。但 owner_id 在 insert 和 update 时都被原样接收自客户端,服务端没有任何守卫把它绑定到创建人。
- 框架版本:15.0.0
- 对象共享模型:
public_read_write
复现(真机,非管理员 worker,isSystem=false)
- insert 伪造属主——worker 用
{ owner_id: 'some_other_user_id' } 建记录 → HTTP 201,原样入库。平台不会把 owner_id 回填为已认证的创建人。 - update 转移属主——worker 把自己的记录更新为
{ owner_id: 'admin_id' } → HTTP 200,属主被转移。
影响
- 用户可以弃权自己创建的记录(规避行级属主门 / 甩锅),或者植入一条挂在他人名下的记录。
- 在
public_read_write 下,行级属主门是唯一强制 update/delete 的机制;掌控 owner_id 就等于掌控谁能改 / 删这条记录。
期望行为
对非特权写入者,owner_id 应当由系统托管:insert 时回填为已认证用户,update 时拒绝(或剥离),除非调用者具备显式的转移 / 重新指派能力。系统上下文(ctx.isSystem)须保持豁免——某些流程合法地创建 owner_id = null 的记录(导入 / 复制 / OAuth 登录 / cron 快照)。
相关
与 #2918(针对平台 / 包托管的 sys_position / sys_capability 行的行写护栏)相邻,但那道护栏不覆盖普通业务对象上的 owner_id。
概述
owner_id是行级属主的锚点(OWD 行级作用域据此判定 update/delete 是否属主)。但owner_id在 insert 和 update 时都被原样接收自客户端,服务端没有任何守卫把它绑定到创建人。public_read_write复现(真机,非管理员 worker,isSystem=false)
{ owner_id: 'some_other_user_id' }建记录 → HTTP 201,原样入库。平台不会把owner_id回填为已认证的创建人。{ owner_id: 'admin_id' }→ HTTP 200,属主被转移。影响
public_read_write下,行级属主门是唯一强制 update/delete 的机制;掌控owner_id就等于掌控谁能改 / 删这条记录。期望行为
对非特权写入者,
owner_id应当由系统托管:insert 时回填为已认证用户,update 时拒绝(或剥离),除非调用者具备显式的转移 / 重新指派能力。系统上下文(ctx.isSystem)须保持豁免——某些流程合法地创建owner_id = null的记录(导入 / 复制 / OAuth 登录 / cron 快照)。相关
与 #2918(针对平台 / 包托管的
sys_position/sys_capability行的行写护栏)相邻,但那道护栏不覆盖普通业务对象上的owner_id。