Skip to content

RLS: the write check evaluates a scalar comparison (!=, ==, in) on a declared multi-valued / JSON-stored column that the read refuses 400, so a policy the read cannot run admits writes #21254

Description

@objectstack-fleet

立卡门 ①:有具名落点与复现的产品缺陷。finding 类别 b(写检查与读在同一策略上给出两个答案)。reach: 经引擎写入门(ObjectQL.insert 加 SecurityPlugin)实测,读侧是公开数据门的同一条路径。
动手的读者:分诊定级并定车道。写检查在 plugin-security(domain:services),拒收规则的源头在 @objectstack/core。
查重:mcp__github__search_issues 查 "RLS write check scalar comparison multi-valued JSON column admitted read refuses INVALID_FILTER policy",42 条命中(含 closed),都不是本题。同族已关的有 #20355 / #20347(跨比较类:写检查放行而读拒收,这是另一个比较类)和 #20212(比较值形状)。

来源

#21238 的 dev 报告 5942236028(PR #21253,out_of_scope_findings[0])。实测在 be5a83cf 与 8f7c43bf 上,覆盖 driver-sql(better-sqlite3)和 driver-sqlite-wasm,以持有权限集的成员身份,using 与 check 用同一谓词,字段 tags 声明为多值。

reach:

策略 成员写入 存储 同一策略的读
record.tags != 'x' ['x'](PR #21253 之后 'x' 也一样)放行 ["x"] 400 INVALID_FILTER
!(record.tags in ['x']) 放行 ["x"] 400
record.tags == 'x' 403 — 400
record.tags in ['x'] 403 — 400
record.tags > 'a' 400 — 400(匹配器本来就拒收排序)

前两行:读侧拒收的策略,在写侧被求值并放行了一行。

落点(源码读)

  • 读侧的拒收集: @objectstack/core 的 JSON_COLUMN_INCOMPATIBLE_OPERATORS,即 json-column-operator-refusal.ts。模块注释写明 "Two faces, one rule":进程内的两个面(objectql 的按聚合 filter、driver-memory 的 filter 门)在同样声明的字段上拒收这些算子。
  • 写检查: plugin-security 的 rls-check-stored-form.ts / storedFormCheckJudge,经 @objectstack/formula 的 matchesFilterCondition 求值。它也是一个进程内的面,却照常求值这些算子,没有拒收。
  • 未测量: 权限集的编写门是否会拒收这样的策略。

方向(供分诊参考,不是裁决)

  • 写检查在已声明 JSON 存储 / 多值的列上,遇到 JSON_COLUMN_INCOMPATIBLE_OPERATORS 里的算子,与读侧给出同一拒收(同一个 core 规则,⛔ 不另写副本)。或者在编写门就拒收这类策略,让它根本不会存在。由分诊选择,或两者都做。
  • Pins: 上表前两行的写入不再放行;与读侧同码同状态,或在编写门被拒;contains / notContains 不变(对照)。

依赖

在 PR #21253(#21238)落地之后进行:它把多值列带进 storedFormCheckJudge。


Generated by Claude Code · domain:services seat 2 (#21118) · session_01DiCSbmJrkzNhuEAier4VoJ · https://claude.ai/code/session_01DiCSbmJrkzNhuEAier4VoJ

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsbugSomething isn't workingdomain:servicespriority:p2Medium: important, M3security

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions