17-bo‘lim
Sxemalar, rollar va RLS
CREATE SCHEMA va search_path, rollar va huquqlar, GRANT va REVOKE, qator darajasidagi xavfsizlik hamda eng kam huquq qoidasi.
Ushbu bo‘lim mundarijasi
Bitta bazada yuzlab jadval bo'lishi mumkin. Ularni tartibga solish uchun sxema, kim nimani ko'rishini boshqarish uchun esa rol va huquq bor.
DROP ROLE IF EXISTS oquvchi_rol;
DROP ROLE IF EXISTS yozuvchi_rol;
DROP ROLE IF EXISTS malika_rol;
CREATE ROLE oquvchi_rol;
CREATE ROLE yozuvchi_rol;
CREATE ROLE malika_rol LOGIN;
CREATE SCHEMA savdo;
CREATE SCHEMA hisobot;
CREATE TABLE savdo.buyurtma (
id int GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
sotuvchi text NOT NULL,
summa numeric(10,2) NOT NULL
);
INSERT INTO savdo.buyurtma (sotuvchi, summa) VALUES
('malika_rol', 250000.00),
('malika_rol', 180000.00),
('nodira_rol', 320000.00),
('aziza_rol', 145000.00);
Sxema nima #
Sxema - bu jadvallar uchun papka. Har bir jadvalning to'liq nomi uchta qismdan iborat:
baza . sxema . jadval
------ ------- -------
dokon . savdo . buyurtma
Bazadagi sxemalarni ko'rish:
SELECT schema_name
FROM information_schema.schemata
WHERE schema_name NOT LIKE 'pg\_%'
ORDER BY schema_name;
schema_name
--------------------
hisobot
information_schema
public
savdo
(4 rows)
search_path #
Har safar savdo.buyurtma deb yozish noqulay. search_path
sxemalarni qaysi tartibda qidirishni belgilaydi:
SHOW search_path;
SET search_path TO savdo, public;
SELECT sotuvchi, summa FROM buyurtma ORDER BY id LIMIT 2;
search_path
-----------------
"$user", public
(1 row)
SET
sotuvchi | summa
------------+-----------
malika_rol | 250000.00
malika_rol | 180000.00
(2 rows)
SET search_path dan keyin buyurtma deb yozish yetarli
bo'ldi.
public sxemasiga ishonmangPostgreSQL 15 gacha har bir foydalanuvchi public sxemasida
jadval yarata olardi. Bu xavfsizlik muammosi edi: yomon
niyatli foydalanuvchi public da sizning jadvalingiz bilan
bir xil nomli jadval yaratib, search_path orqali
so'rovlaringizni o'z jadvaliga yo'naltirishi mumkin edi.
PostgreSQL 15 dan boshlab bu odatiy holda taqiqlangan.
Ishonchli yozuv qoidasi:
| Vaziyat | Yozuv |
|---|---|
| Skript, migratsiya, funksiya | To'liq nom: savdo.buyurtma |
Qo'lda psql da ishlash | search_path qulay |
Migratsiya fayllarida har doim to'liq nom yozing - shunda
kimning search_path i qanday bo'lishidan qat'i nazar,
skript to'g'ri jadvalga tegadi.
Rollar #
PostgreSQL da "foydalanuvchi" va "guruh" alohida tushuncha emas - ikkalasi ham rol. Farq bitta xususiyatda:
| Xususiyat | Ma'nosi |
|---|---|
LOGIN | Rol bazaga ulana oladi - ya'ni "foydalanuvchi" |
NOLOGIN | Ulana olmaydi - ya'ni "guruh" |
SUPERUSER | Hamma tekshiruvdan o'tib ketadi |
CREATEDB | Yangi baza yarata oladi |
CREATEROLE | Yangi rol yarata oladi |
SELECT rolname, rolcanlogin AS kira_oladi, rolsuper AS super
FROM pg_roles
WHERE rolname LIKE '%\_rol'
ORDER BY rolname;
rolname | kira_oladi | super
--------------+------------+-------
malika_rol | t | f
oquvchi_rol | f | f
yozuvchi_rol | f | f
(3 rows)
GRANT va REVOKE #
Huquq berish va olib tashlash:
GRANT USAGE ON SCHEMA savdo TO oquvchi_rol;
GRANT SELECT ON savdo.buyurtma TO oquvchi_rol;
GRANT oquvchi_rol TO yozuvchi_rol;
GRANT INSERT, UPDATE ON savdo.buyurtma TO yozuvchi_rol;
SELECT grantee, privilege_type
FROM information_schema.table_privileges
WHERE table_name = 'buyurtma' AND grantee LIKE '%\_rol'
ORDER BY grantee, privilege_type;
GRANT
GRANT
GRANT ROLE
GRANT
grantee | privilege_type
--------------+----------------
oquvchi_rol | SELECT
yozuvchi_rol | INSERT
yozuvchi_rol | UPDATE
(3 rows)
GRANT oquvchi_rol TO yozuvchi_rol qatori muhim: u
yozuvchi_rol ga oquvchi_rol ning hamma huquqini
meros qilib beradi.
Ikkita yondashuv bor:
| Yomon | Yaxshi |
|---|---|
Har xodimga alohida GRANT | Guruh rolga GRANT |
| Xodim ketsa - qaysi huquqni olib tashlash noma'lum | REVOKE guruh FROM xodim - tamom |
Yangi jadval - hammaga qaytadan GRANT | Guruhga bir marta |
To'g'ri tuzilma:
malika_rol -> yozuvchi_rol -> oquvchi_rol
(odam) (guruh) (guruh)
Odam rollari faqat guruhga ulanadi, huquq esa faqat guruhlarda bo'ladi.
Huquqni olib tashlash:
GRANT SELECT, INSERT ON savdo.buyurtma TO malika_rol;
REVOKE INSERT ON savdo.buyurtma FROM malika_rol;
SELECT privilege_type
FROM information_schema.table_privileges
WHERE table_name = 'buyurtma' AND grantee = 'malika_rol'
ORDER BY privilege_type;
GRANT
REVOKE
privilege_type
----------------
SELECT
(1 row)
Kelajakdagi jadvallar #
Klassik muammo: bugun GRANT qildingiz, ertaga yangi jadval
yaratildi - va u yangi jadvalda huquq yo'q.
Yechim - ALTER DEFAULT PRIVILEGES:
ALTER DEFAULT PRIVILEGES IN SCHEMA savdo
GRANT SELECT ON TABLES TO oquvchi_rol;
CREATE TABLE savdo.tolov (
id int GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
summa numeric(10,2) NOT NULL
);
SELECT grantee, privilege_type
FROM information_schema.table_privileges
WHERE table_name = 'tolov' AND grantee LIKE '%\_rol'
ORDER BY grantee;
ALTER DEFAULT PRIVILEGES
CREATE TABLE
grantee | privilege_type
-------------+----------------
oquvchi_rol | SELECT
(1 row)
Jadval GRANT dan keyin yaratilgan bo'lsa ham,
oquvchi_rol unga SELECT huquqiga ega.
RLS - qator darajasidagi xavfsizlik #
GRANT butun jadvalga ruxsat beradi. Ba'zan esa
foydalanuvchi faqat o'z qatorlarini ko'rishi kerak.
Bunday holatda RLS (Row Level Security) ishlatiladi:
GRANT USAGE ON SCHEMA savdo TO malika_rol;
GRANT SELECT ON savdo.buyurtma TO malika_rol;
ALTER TABLE savdo.buyurtma ENABLE ROW LEVEL SECURITY;
CREATE POLICY oz_buyurtmasi ON savdo.buyurtma
FOR SELECT
USING (sotuvchi = current_user);
SET ROLE malika_rol;
SELECT sotuvchi, summa FROM savdo.buyurtma ORDER BY id;
RESET ROLE;
GRANT
GRANT
ALTER TABLE
CREATE POLICY
SET
sotuvchi | summa
------------+-----------
malika_rol | 250000.00
malika_rol | 180000.00
(2 rows)
RESET
Jadvalda to'rtta qator bor edi, lekin malika_rol faqat
ikkitasini ko'rdi - qolganlari boshqa sotuvchilarniki.
USING shartini baza har bir SELECT ga avtomatik
qo'shadi. Foydalanuvchi buni chetlab o'tolmaydi - WHERE
yozmasa ham, shart baribir qo'llanadi.
Egasi esa hammasini ko'radi:
ALTER TABLE savdo.buyurtma ENABLE ROW LEVEL SECURITY;
CREATE POLICY oz_buyurtmasi ON savdo.buyurtma
FOR SELECT USING (sotuvchi = current_user);
SELECT count(*) AS egasi_koradigan FROM savdo.buyurtma;
ALTER TABLE
CREATE POLICY
egasi_koradigan
-----------------
4
(1 row)
Yuqoridagi natija chalkashtirishi mumkin: siyosat yoqilgan, lekin to'rttala qator ham ko'rindi.
Sabab: jadval egasi odatiy holda RLS dan chetlab o'tadi. Bu ataylab qilingan - aks holda egasi o'z jadvalidagi ma'lumotni ko'ra olmay qolishi mumkin edi.
Buni o'zgartirish mumkin:
ALTER TABLE savdo.buyurtma FORCE ROW LEVEL SECURITY;
Undan ham muhimi: SUPERUSER rol RLS ni butunlay
e'tiborsiz qoldiradi va FORCE ham unga ta'sir qilmaydi.
Shuning uchun dastur bazaga hech qachon superuser sifatida ulanmasligi kerak. RLS ni sinaganda ham oddiy rol bilan tekshiring - superuser bilan sinov hech narsani isbotlamaydi.
Siyosat turlari #
| Amal | USING | WITH CHECK |
|---|---|---|
SELECT | Qaysi qator ko'rinadi | - |
UPDATE | Qaysi qatorni tanlash mumkin | Natija qanday bo'lishi kerak |
DELETE | Qaysi qatorni o'chirish mumkin | - |
INSERT | - | Qanday qator qo'shish mumkin |
WITH CHECK bo'lmasa, foydalanuvchi o'z qatorini boshqa
odam nomiga o'tkazib yuborishi mumkin - shuning uchun
UPDATE siyosatida ikkalasi ham kerak.
Eng kam huquq qoidasi #
| Rol | Nimaga ruxsat |
|---|---|
| Veb-dastur | SELECT, INSERT, UPDATE - kerakli jadvallarda |
| Hisobot | Faqat SELECT |
| Migratsiya | CREATE, ALTER - faqat joylashtirish vaqtida |
| Superuser | Faqat administrator, faqat qo'lda |
Dastur superuser bilan ulansa, dasturdagi bitta SQL in'ektsiya butun klasterni qo'lga olish imkonini beradi. Oddiy rol bilan esa zarar faqat shu rolning huquqi bilan chegaralanadi.
- Ikkita sxema yarating va har birida jadval oching.
- Jadvalga to'liq nom bilan murojaat qiling.
search_pathni o'zgartirib, qisqa nom bilan so'rang.- Migratsiyada nega to'liq nom yozish kerakligini yozing.
- Bitta
NOLOGINguruh rol yarating. - Unga
SELECThuquqini bering. - Odam rolini shu guruhga qo'shing.
ALTER DEFAULT PRIVILEGESbilan kelajakdagi jadvalni qamrang.- RLS yoqib,
current_userbo'yicha siyosat yozing. - Nima uchun jadval egasi siyosatni chetlab o'tishini tushuntiring.
Xulosa #
- Sxema - jadvallar uchun papka; to'liq nom
sxema.jadvalko'rinishida. - Ikki sxemada bir xil nomli jadval bo'lishi mumkin.
search_pathqidiruv tartibini belgilaydi - qo'lda ishlashda qulay.- Migratsiya va funksiyalarda har doim to'liq nom yozing.
- PostgreSQL da foydalanuvchi va guruh - ikkalasi ham rol; farq
LOGINda. - Huquqni odamga emas, guruh rolga bering.
GRANT guruh TO odamhuquqlarni meros qilib beradi.ALTER DEFAULT PRIVILEGESkelajakda yaratiladigan jadvallarni qamrab oladi.- RLS qator darajasida filtr qo'yadi va uni chetlab o'tib bo'lmaydi.
- Lekin jadval egasi va ayniqsa superuser RLS dan ozod - dastur superuser bilan ulanmasin.
Keyingi bo'limda PL/pgSQL funksiyalari va triggerlarni ko'ramiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.