--liquibase formatted sql -- PANELS · panels_product.iam (Postgres) · Row Level Security (Fase 4b) -- -- Defensa en profundidad contra el bug de IDOR cross-tenant encontrado en -- la revisión de seguridad: aunque un handler olvide el WHERE tenant_id=?, -- Postgres ya no devuelve/permite escribir filas de otro tenant. -- -- Cómo se activa: el rol de runtime (panels_iam_app) NO es dueño de la -- tabla (panels_iam_owner sí lo es), así que ENABLE ROW LEVEL SECURITY ya -- restringe automáticamente a panels_iam_app sin necesitar FORCE (FORCE -- haría que la política también aplique al dueño, lo cual rompería las -- migraciones/backfills que sí necesitan ver todos los tenants). -- -- El valor de comparación viene de un parámetro de sesión que la API fija -- al inicio de cada transacción: SET LOCAL app.tenant_id = ''. Si el -- código olvida fijarlo, current_setting(...) devuelve NULL y la -- comparación "tenant_id = NULL" es siempre falsa -- es decir, "fail -- closed": sin tenant_id explícito no se ve ni se escribe ninguna fila, -- en vez de exponer todo por defecto. --changeset panel:iam-002a-rls-users endDelimiter:; splitStatements:true --preconditions onFail:MARK_RAN --precondition-sql-check expectedResult:0 SELECT COUNT(*) FROM pg_policies WHERE schemaname='iam' AND tablename='users' AND policyname='tenant_isolation' ALTER TABLE iam.users ENABLE ROW LEVEL SECURITY; CREATE POLICY tenant_isolation ON iam.users USING (tenant_id = NULLIF(current_setting('app.tenant_id', true), '')::integer) WITH CHECK (tenant_id = NULLIF(current_setting('app.tenant_id', true), '')::integer);