- analysis/·source-index·state.json 을 final/document.md 제2부·제3부로 접었다. SSOT 는 하나다 - 파일럿 — commit-ambiguity-as-a-result 를 새 기준으로 재선별. 후보 14 → 글감 5 (PROMOTE 5 · MERGE_INTO 3 · KEEP_IN_SSOT 4 · 보류 2). 기록 5건을 다시 썼고 그림 1개를 techviz 로 만들었다 - 재선별이 잡은 것: 제1부 §6.2·§11.1 이 자기 §13.2 와 어긋나 있었다(레인을 안 돌렸다 vs 돌렸다) — 정정. 이미 답이 나와 있던 Question 을 HEAD 재실행 질문으로 다시 세웠다. Concept 이 인용한 코드가 SSOT 에 없어 뺐다 - candidateScope·sourceRepository 기록. 나머지 43개 주제는 재선별 대기(PENDING 905) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
4.6 KiB
kind, slug, title, topic, project, status, sourceRevision, rootTreeNode, evidenceCapturedOn, assets, evidence, source
| kind | slug | title | topic | project | status | sourceRevision | rootTreeNode | evidenceCapturedOn | assets | evidence | source | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| CASE | three-ways-rls-does-nothing | RLS가 아무것도 하지 않는 세 가지 방법 | multitenancy-isolation | clean-architecture-backend-template | 게시 전 | 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 | case:three-ways-rls-does-nothing | 2026-09-01 |
|
|
|
RLS가 아무것도 하지 않는 세 가지 방법
정책 검증기가 행 수준 보안이 조용히 무력화되는 세 경로를 전부 확인한다. 다만 검증기 자신이 보호되어야 할 테이블의 부재를 성공으로 인정하는 결함을 갖는다.
관계
- RLS가 성립하기 위한 세 전제 이 검증기가 확인하는 세 조건이다.
- Hibernate filter는 보안 경계가 아니다 같은 격리 문제를 ORM 기능으로 풀려 할 때의 규칙이다.
- tenant 컬럼이 있는 테이블의 모든 unique 제약에 그 컬럼이 들어가야 한다 같은 마이그레이션이 함께 다룬 축이다.
문제
행 수준 보안은 설정이 올바르게 보이면서 아무것도 하지 않을 수 있다. 그 경로가 셋이다.
정책이 없거나 테이블에 RLS 가 활성화되지 않았다 런타임 롤이 우회 속성을 갖는다 런타임 롤이 그 테이블을 소유한다
셋 다 같은 결과를 만든다. 모든 쿼리가 모든 테넌트의 행을 돌려주면서 정책은 올바르게 설정된 것처럼 보인다.
결론
검증기가 세 경로를 전부 확인한다.
시스템 카탈로그에서 테이블별로 RLS 활성 여부와 강제 여부를 읽고, 롤의 우회 속성을 확인하며, 소유 관계를 본다.
세 번째가 가장 놓치기 쉽다. 소유자는 기본적으로 자기 정책에서 면제되고, 소유자는 흔히 마이그레이션 롤이며, 그것이 사람들이 테스트하는 롤이다.
같은 축의 문제가 유니크 인덱스에도 있고 마이그레이션 주석이 그것을 적는다. 테넌트 격리가 컬럼에 의존하면 그 테이블의 모든 유일성 요구에 그 컬럼이 들어가야 한다. 값만으로 걸린 유니크 인덱스는 다른 테넌트가 그 값을 이미 썼다는 이유로 한 테넌트의 삽입을 실패시키고, 그것은 버그이자 정보 유출이다.
다만 검증기 자신에게 결함이 있다. 반드시 보호되어야 할 테이블이 조회 결과에 없을 때 그것을 성공으로 인정한다. 즉 테이블 이름이 바뀌거나 조회 조건이 어긋나면 검증이 통과한다.
검증 환경
데이터베이스 : PostgreSQL 확인 방식 : 검증기가 검사하는 세 조건과 마이그레이션 주석 확인 소스 수정 : x
재현 조건
- 정책 검증기의 클래스 javadoc 을 읽는다. 세 경로가 열거되어 있다.
- 검증기가 실행하는 카탈로그 조회를 확인한다.
- 마이그레이션의 유니크 인덱스 주석을 읽는다.
- 보호 대상 테이블이 조회 결과에 없을 때의 처리를 확인한다.
본문
RlsPolicyVerifier가 RLS가 조용히 무력화되는 세 경로를 전부 확인한다 — policy 없음/RLS 미활성 · 런타임 롤이 BYPASSRLS 보유 · 런타임 롤이 테이블을 소유(FORCE 없으면 면제).
RlsPolicyVerifier 참조 위치
:::evidence key="three-ways-rls-does-nothing" alt="코드베이스에서 RlsPolicyVerifier 를 검색한 출력 2줄. 이 기록이 세는 참조가 그 출력에 그대로 보인다." caption="RlsPolicyVerifier 코드베이스 검색 — 2줄 · exit 0" zoom="true" :::
세 번째가 가장 놓치기 쉽다
소유자는 정책을 우회하는 것이 아니라 애초에 적용 대상이 아니다.
unique index 에도 같은 축의 주석이 있다
tenant 격리가 컬럼에 의존하면 그 테이블의 모든 uniqueness 요구에 그 컬럼이 들어가야 하고, (value)만의 unique index는 다른 tenant가 그 값을 썼다는 이유로 insert를 실패시켜 버그이자 정보 유출이 된다.
verifier 자신에게도 결함이 있다
final/document.md#a05 §97이 기록하듯 "반드시 보호돼야 하는 table"의 부재를 성공으로 인정한다.
확인하지 못한 것
세 조건을 하나씩 깨서 검증기가 실제로 잡는지 확인하지 않았다. 실제 RLS 환경을 세우지 않았다.