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.

🕑 14 daqiqa o‘qish 📄 851 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Sxema nima
  2. search_path
  3. Rollar
  4. GRANT va REVOKE
  5. Kelajakdagi jadvallar
  6. RLS - qator darajasidagi xavfsizlik
  7. Siyosat turlari
  8. Eng kam huquq qoidasi
  9. Xulosa

Bitta bazada yuzlab jadval bo'lishi mumkin. Ularni tartibga solish uchun sxema, kim nimani ko'rishini boshqarish uchun esa rol va huquq bor.

SQL
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:

Natija
baza  .  sxema  .  jadval
------   -------   -------
dokon   .  savdo  .  buyurtma
Nom uch bosqichdan iborat Baza: dokon Sxema: savdo savdo.buyurtma savdo.mijoz savdo.tolov kunlik ish jadvallari Sxema: hisobot hisobot.oylik hisobot.buyurtma nomi bir xil bo'lsa ham bu boshqa jadval faqat o'qish uchun
Ikki sxemada bir xil nomli jadval bo'lishi mumkin - ular to'qnashmaydi

Bazadagi sxemalarni ko'rish:

SQL
SELECT schema_name
FROM information_schema.schemata
WHERE schema_name NOT LIKE 'pg\_%'
ORDER BY schema_name;
Natija
    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:

SQL
SHOW search_path;

SET search_path TO savdo, public;

SELECT sotuvchi, summa FROM buyurtma ORDER BY id LIMIT 2;
Natija
   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 ishonmang

PostgreSQL 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:

VaziyatYozuv
Skript, migratsiya, funksiyaTo'liq nom: savdo.buyurtma
Qo'lda psql da ishlashsearch_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:

XususiyatMa'nosi
LOGINRol bazaga ulana oladi - ya'ni "foydalanuvchi"
NOLOGINUlana olmaydi - ya'ni "guruh"
SUPERUSERHamma tekshiruvdan o'tib ketadi
CREATEDBYangi baza yarata oladi
CREATEROLEYangi rol yarata oladi
SQL
SELECT rolname, rolcanlogin AS kira_oladi, rolsuper AS super
FROM pg_roles
WHERE rolname LIKE '%\_rol'
ORDER BY rolname;
Natija
   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:

SQL
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;
Natija
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.

Huquqlarni foydalanuvchiga emas, guruhga bering

Ikkita yondashuv bor:

YomonYaxshi
Har xodimga alohida GRANTGuruh rolga GRANT
Xodim ketsa - qaysi huquqni olib tashlash noma'lumREVOKE guruh FROM xodim - tamom
Yangi jadval - hammaga qaytadan GRANTGuruhga bir marta

To'g'ri tuzilma:

Natija
malika_rol  ->  yozuvchi_rol  ->  oquvchi_rol
(odam)          (guruh)           (guruh)

Odam rollari faqat guruhga ulanadi, huquq esa faqat guruhlarda bo'ladi.

Huquqni olib tashlash:

SQL
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;
Natija
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:

SQL
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;
Natija
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:

SQL
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;
Natija
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:

SQL
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;
Natija
ALTER TABLE
CREATE POLICY
 egasi_koradigan
-----------------
               4
(1 row)
Jadval egasi RLS dan ozod

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:

Natija
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 #

AmalUSINGWITH CHECK
SELECTQaysi qator ko'rinadi-
UPDATEQaysi qatorni tanlash mumkinNatija qanday bo'lishi kerak
DELETEQaysi 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 #

RolNimaga ruxsat
Veb-dasturSELECT, INSERT, UPDATE - kerakli jadvallarda
HisobotFaqat SELECT
MigratsiyaCREATE, ALTER - faqat joylashtirish vaqtida
SuperuserFaqat 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.

Amaliy topshiriq
  1. Ikkita sxema yarating va har birida jadval oching.
  2. Jadvalga to'liq nom bilan murojaat qiling.
  3. search_path ni o'zgartirib, qisqa nom bilan so'rang.
  4. Migratsiyada nega to'liq nom yozish kerakligini yozing.
  5. Bitta NOLOGIN guruh rol yarating.
  6. Unga SELECT huquqini bering.
  7. Odam rolini shu guruhga qo'shing.
  8. ALTER DEFAULT PRIVILEGES bilan kelajakdagi jadvalni qamrang.
  9. RLS yoqib, current_user bo'yicha siyosat yozing.
  10. Nima uchun jadval egasi siyosatni chetlab o'tishini tushuntiring.

Xulosa #

  • Sxema - jadvallar uchun papka; to'liq nom sxema.jadval ko'rinishida.
  • Ikki sxemada bir xil nomli jadval bo'lishi mumkin.
  • search_path qidiruv tartibini belgilaydi - qo'lda ishlashda qulay.
  • Migratsiya va funksiyalarda har doim to'liq nom yozing.
  • PostgreSQL da foydalanuvchi va guruh - ikkalasi ham rol; farq LOGIN da.
  • Huquqni odamga emas, guruh rolga bering.
  • GRANT guruh TO odam huquqlarni meros qilib beradi.
  • ALTER DEFAULT PRIVILEGES kelajakda 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.

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.