Row Level Security — RLS, policy yaratish

~20 daq · PostgreSQL · Xavfsizlik va Boshqaruv

Multi-tenant ilova: har foydalanuvchi faqat o'z ma'lumotlarini ko'rishi kerak. Ilovada WHERE foydalanuvchi_id = $current_user qo'shish mumkin — lekin bir joyda unutilsa, boshqa foydalanuvchi ma'lumoti ko'rinadi.

Row Level Security (RLS) — bu tekshiruvni database darajasiga tushirish. Qaysi user bo'lishidan qat'iy nazar — faqat o'z qatorlari ko'rinadi.


RLS yoqish

-- Jadvalda RLS yoqish
ALTER TABLE buyurtmalar ENABLE ROW LEVEL SECURITY;

-- RLS yoqilgan jadvalda superuser emas foydalanuvchilar hech nima ko'rmaydi
-- Policy bo'lmasa — barcha qatorlar bloklanadi

Policy yaratish

-- Foydalanuvchi faqat o'z buyurtmalarini ko'radi
CREATE POLICY foydalanuvchi_buyurtmalari
ON buyurtmalar
FOR SELECT
USING (foydalanuvchi_id = current_user_id());
-- current_user_id() — joriy session dan foydalanuvchi ID

current_user va session variables

Joriy foydalanuvchi ID ni uzatish:

-- Session o'zgaruvchisi orqali
SET app.current_user_id = '42';

-- Policy da ishlatish
CREATE POLICY foydalanuvchi_buyurtmalari
ON buyurtmalar
FOR SELECT
USING (foydalanuvchi_id = current_setting('app.current_user_id')::INT);

Node.js da:

await client.query(`SET app.current_user_id = ${userId}`);
const { rows } = await client.query('SELECT * FROM buyurtmalar');
// Faqat shu userId ning buyurtmalari qaytadi

Turli operatsiyalar uchun policy

-- SELECT — o'z qatorlarini ko'rish
CREATE POLICY buyurtma_select ON buyurtmalar
FOR SELECT USING (foydalanuvchi_id = current_setting('app.user_id')::INT);

-- INSERT — faqat o'ziga qo'shishi mumkin
CREATE POLICY buyurtma_insert ON buyurtmalar
FOR INSERT WITH CHECK (foydalanuvchi_id = current_setting('app.user_id')::INT);

-- UPDATE — faqat o'zinkini
CREATE POLICY buyurtma_update ON buyurtmalar
FOR UPDATE USING (foydalanuvchi_id = current_setting('app.user_id')::INT);

-- DELETE — o'chirish taqiqlangan (policy yo'q = taqiq)

Admin — barcha qatorlarni ko'rish

-- Admin uchun alohida policy
CREATE POLICY admin_barcha ON buyurtmalar
FOR ALL
USING (current_setting('app.user_role') = 'admin');

Supabase va RLS

Supabase RLS ni keng ishlatadi — har jadvalda yoqiladi, auth.uid() orqali:

CREATE POLICY "Foydalanuvchi o'z profilini ko'radi"
ON profillar FOR SELECT
USING (auth.uid() = foydalanuvchi_id);

Tez-tez uchraydigan xatolar

Superuser RLS ni e'tiborga olmaydi:

-- postgres superuser RLS ni o'tkazib yuboradi
-- Test qilish uchun oddiy user bilan ulanish

RLS FORCE — superuser uchun ham:

ALTER TABLE buyurtmalar FORCE ROW LEVEL SECURITY;
-- Endi superuser ham policyga bo'ysunadi

Xulosa

ALTER TABLE jadval ENABLE ROW LEVEL SECURITY;

CREATE POLICY nom ON jadval
FOR SELECT | INSERT | UPDATE | DELETE | ALL
USING (/* mavjud qator sharti */)
WITH CHECK (/* yangi qator sharti */);

DROP POLICY nom ON jadval;

-- Session o'zgaruvchisi
SET app.user_id = '42';
current_setting('app.user_id')::INT

RLS — database darajasida qator filtrash. Ilovada WHERE unutilsa ham — database himoya qiladi.


Keyingi dars

54-dars: SQL Injection — qanday himoyalanish, parameterized query