Mundarija (32)
- Bu darsda
- 1. Nega bu kerak?
- 2. Rol nima
- 2.1 Foydalanuvchi va guruh — bitta tushuncha
- 2.2 Kanondagi to'rt rol
- 3. Huquqlar uch qavatda
- 3.1 public sxema va PostgreSQL 15
- 4. API roli amalda
- 5. Hisobot roli va SET ROLE tuzog'i
- 5.1 ALTER ROLE … SET
- 5.2 SET ROLE sozlamalarni qo'llamaydi
- 5.3 Nega hisobotga BYPASSRLS
- 6. Migratsiya roli va egalik
- 6.1 "must be owner"
- 6.2 ALTER DEFAULT PRIVILEGES — kelajak uchun
- 6.3 Kanon xatosi va "qo'llangan migratsiya o'zgarmaydi" qoidasi
- 7. Yana bir topilma: REVOKE CONNECT faqat bitta bazada
- 8. Parollar haqida
- 9. Ko'p uchraydigan xatolar
- 9.1 Ilova superuser bilan ulangan
- 9.2 GRANT … ON ALL TABLES dan keyin yangi jadval huquqsiz
- 9.3 SET ROLE bilan sozlamani tekshirish
- 9.4 Sequence'ni unutish
- 9.5 Migratsiya va ilova bitta rol
- 10. Mashqlar
- 1-mashq (oson): Faqat o'qiydigan rol
- 2-mashq (o'rta): Guruh va a'zo
- 3-mashq (qiyin): Default privileges
- 11. Loyiha qadami: rollar migratsiyasi (holat 11)
- 12. Real ishda
- Xulosa
- Manbalar
PostgreSQL rollar va huquqlar: GRANT, REVOKE va eng kam huquq
Qisqacha: Ilova bazaga superuser bilan ulanmasligi kerak. To'g'ri tizim — bir nechta rol: migratsiya roli (jadval yaratadi va o'zgartiradi), ilova roli (faqat SELECT/INSERT/UPDATE/DELETE, RLS ostida), hisobot roli (faqat o'qish,
statement_timeoutbilan). HuquqlarGRANT/REVOKEbilan beriladi, kelajakdagi jadvallar uchun —ALTER DEFAULT PRIVILEGES. Ehtiyot:SET ROLErol sozlamalarini qo'llamaydi,REVOKE CONNECTfaqat bitta bazaga ta'sir qiladi.
Bu darsda
CREATE ROLE,LOGIN, guruh rollari va a'zolikni tushuntirasiz.- Baza, sxema va jadval darajasidagi huquqlarni
GRANT/REVOKEbilan boshqarasiz. - PostgreSQL 15 dagi
publicsxema o'zgarishini vaALTER DEFAULT PRIVILEGESni bilasiz. - Read-only hisobot rolini to'g'ri qurasiz va
SET ROLEtuzog'ini taniysiz. - Migratsiya roli va ilova roli nega alohida ekanini va egalik (owner) masalasini bilasiz.
Oldin bilishingiz kerak: psql chuqur, SQL tili va buyruq turlari (GRANT, SET ROLE bilan birinchi tanishuv), Row Level Security.
1. Nega bu kerak?
26-qismdan beri vazifalar-api bazaga postgres bilan ulanadi. postgres — superuser: u istalgan jadvalni o'chira oladi, RLS'ni chetlab o'tadi, server fayllarini o'qiy oladi. Agar API'da bitta SQL injection teshigi qolsa (Parametrli so'rovlar va SQL injection), hujumchi ham superuser bo'ladi.
Eng kam huquq (least privilege) tamoyili: har ishtirokchiga faqat o'z ishi uchun kerak bo'lgan huquq. O'xshatish: mehmonxona kartalari. Mehmon kartasi faqat o'z xonasini ochadi. Farrosh kartasi — hamma xonani, lekin seyfni emas. Direktor kartasi — hammasini. Mehmonga direktor kartasini bermaysiz — hatto u yaxshi odam bo'lsa ham: karta yo'qolishi mumkin.
Oldingi darsda RLS siyosatlarini yozdik va "ilova superuser bo'lsa, ular ishlamaydi" dedik. Bu darsda shu bo'shliqni yopamiz.
Bu darsdagi so'rovlarni biz ishga tushirdik: PostgreSQL 17.6, kanon holat 11 sxemasi (106-rollar.sql qo'llangan). Kanon (PostgreSQL 18.6) bilan chiqish bir xil (kanon o'lchovi, IlmHamroh, 2026-10).
2. Rol nima
2.1 Foydalanuvchi va guruh — bitta tushuncha
Postgres'da rol (role) — ham foydalanuvchi, ham guruh. Farq atributlarda:
| Atribut | Ma'nosi |
|---|---|
LOGIN |
bu rol bilan ulanish mumkin ("foydalanuvchi") |
NOLOGIN |
ulanib bo'lmaydi — huquqlar yig'indisi ("guruh") |
SUPERUSER |
hamma tekshiruvdan ozod |
BYPASSRLS |
RLS'ni chetlab o'tadi |
CONNECTION LIMIT n |
bir vaqtda ko'pi bilan n ulanish |
IN ROLE g |
yaratilganda g guruhiga a'zo |
Rollar klaster darajasida — bitta serverdagi hamma bazalar uchun umumiy. Huquqlar esa har baza va har obyektga alohida.
2.2 Kanondagi to'rt rol
Kanon to'rt rolli tizim qurgan:
SELECT rolname, rolsuper, rolinherit, rolcanlogin, rolbypassrls,
rolconnlimit, rolconfig
FROM pg_roles WHERE rolname LIKE 'vazifalar_%' ORDER BY 1; rolname | rolsuper | rolinherit | rolcanlogin | rolbypassrls | rolconnlimit | rolconfig
----------------------+----------+------------+-------------+--------------+--------------+----------------------------------------------------------
vazifalar_api | f | t | t | f | 40 |
vazifalar_hisobot | f | t | t | t | 5 | {statement_timeout=30s,default_transaction_read_only=on}
vazifalar_ilova | f | t | f | f | -1 |
vazifalar_migratsiya | f | t | t | f | -1 |
(4 rows)Diagrammada kim nima qiladi:
flowchart LR
M["vazifalar_migratsiya"] -->|"CREATE, ALTER"| S["public sxema"]
I["vazifalar_ilova<br/>NOLOGIN guruh"] -->|"DML + RLS"| J["jadvallar"]
A["vazifalar_api<br/>LOGIN, 40 ulanish"] -->|"a'zo"| I
H["vazifalar_hisobot<br/>read-only"] -->|"SELECT, BYPASSRLS"| J
S --> Jvazifalar_ilova— guruh (NOLOGIN). Barcha DML huquqlari va RLS siyosatlari unga berilgan (Row Level Security darsidagi105).vazifalar_api— API jarayoni shu bilan ulanadi. O'zida huquq yo'q — uvazifalar_ilovaa'zosi varolinherit = t(a'zolik huquqlarini meros oladi).vazifalar_hisobot— analitika uchun: hammasini o'qiydi (BYPASSRLS— ongli qaror, pastda), yoza olmaydi, ko'pi bilan 5 ulanish, so'rov 30 soniyadan oshmaydi.vazifalar_migratsiya— sxemani o'zgartiradi. Ilova u bilan ishlamaydi.
Nega guruh va login alohida? Ertaga ikkinchi xizmat paydo bo'lsa (masalan, fon vazifalari ishchisi — 29-qism), unga vazifalar_ishchi LOGIN IN ROLE vazifalar_ilova yetadi — huquqlarni qayta yozish shart emas. Har xizmat o'z nomi bilan ulanadi — log'da "kim nima qildi" ko'rinadi.
A'zolik katalogda:
SELECT r.rolname AS rol, m.rolname AS azosi
FROM pg_auth_members a
JOIN pg_roles r ON r.oid = a.member
JOIN pg_roles m ON m.oid = a.roleid
WHERE r.rolname LIKE 'vazifalar_%' ORDER BY 1; rol | azosi
---------------+-----------------
vazifalar_api | vazifalar_ilova
(1 row)Tekshirib ko'ring: Nega
vazifalar_ilovaniNOLOGINqilish kerak edi?LOGINbo'lsa nima yomon?
Javob
Guruh — huquqlar to'plami, uning nomi bilan hech kim ulanmasligi kerak. LOGIN bo'lsa, unga parol berilishi, parol sizishi va kimdir "umumiy" hisob bilan ulanishi mumkin — log'da kim ekanini bilib bo'lmaydi. Kanon tekshirgan: psql -U vazifalar_ilova → role "vazifalar_ilova" is not permitted to log in.
3. Huquqlar uch qavatda
Biror jadvalga yetish uchun uch eshikdan o'tish kerak:
- Baza —
CONNECT(ulanish),TEMPORARY(vaqtinchalik jadval),CREATE(sxema yaratish). - Sxema —
USAGE(ichidagi obyektlarni ko'rish),CREATE(obyekt yaratish). - Obyekt — jadvalga
SELECT,INSERT,UPDATE,DELETE,TRUNCATE,REFERENCES,TRIGGER; sequence'gaUSAGE; funksiyagaEXECUTE.
PUBLIC — "hamma rollar" degan maxsus nom. Sukut bo'yicha PUBLIC'da: har bazaga CONNECT va TEMPORARY, har funksiyaga EXECUTE. Kanon migratsiyasi bazadan PUBLIC'ni olib tashlaydi:
DO $$ BEGIN
EXECUTE format(
'REVOKE CONNECT, TEMPORARY ON DATABASE %I FROM PUBLIC',
current_database());
EXECUTE format(
'GRANT CONNECT ON DATABASE %I TO vazifalar_migratsiya, '
|| 'vazifalar_api, vazifalar_hisobot', current_database());
END $$;format('%I', …) — nomni identifikator sifatida xavfsiz qo'yadi (qo'shtirnoq kerak bo'lsa — qo'yadi). Baza nomi qat'iy yozilmagan — kanon xatosi shu yerda tuzatilgan: birinchi variantda vazifalar yozilgan edi, va migratsiya boshqa nomli bazada (tekshiruv uchun quriladigan tekshiruv) noto'g'ri bazaga ta'sir qilardi.
Jadval huquqlari katalogdan (\dp ning SQL shakli):
SELECT table_name, grantee,
string_agg(privilege_type, ',' ORDER BY privilege_type)
AS huquqlar
FROM information_schema.role_table_grants
WHERE table_schema = 'public' AND grantee LIKE 'vazifalar_%'
GROUP BY 1, 2 ORDER BY 1, 2; table_name | grantee | huquqlar
------------------+-------------------+-----------------------------
faol_vazifalar | vazifalar_hisobot | SELECT
faol_vazifalar | vazifalar_ilova | SELECT
foydalanuvchilar | vazifalar_hisobot | SELECT
foydalanuvchilar | vazifalar_ilova | DELETE,INSERT,SELECT,UPDATE
izohlar | vazifalar_hisobot | SELECT
izohlar | vazifalar_ilova | DELETE,INSERT,SELECT,UPDATE
teglar | vazifalar_hisobot | SELECT
teglar | vazifalar_ilova | DELETE,INSERT,SELECT,UPDATE
vazifa_tarixi | vazifalar_hisobot | SELECT
vazifa_tarixi | vazifalar_ilova | INSERT
vazifa_teglari | vazifalar_hisobot | SELECT
vazifa_teglari | vazifalar_ilova | DELETE,INSERT,SELECT,UPDATE
vazifalar | vazifalar_hisobot | SELECT
vazifalar | vazifalar_ilova | DELETE,INSERT,SELECT,UPDATE
(14 rows)Ilovada TRUNCATE yo'q (butun jadvalni bir zumda tozalash — ilovaga kerak emas), vazifa_tarixi da faqat INSERT (trigger yozadi, ilova tarixni o'qimaydi va o'zgartirmaydi).
Bitta savol bilan tekshirish — has_*_privilege funksiyalari:
SELECT has_database_privilege('vazifalar_api',
current_database(), 'CONNECT') AS api_connect,
has_database_privilege('public',
current_database(), 'CONNECT') AS public_connect,
has_schema_privilege('vazifalar_api', 'public', 'CREATE')
AS api_create,
has_schema_privilege('vazifalar_migratsiya', 'public',
'CREATE')
AS migratsiya_create; api_connect | public_connect | api_create | migratsiya_create
-------------+----------------+------------+-------------------
t | f | f | t
(1 row)3.1 public sxema va PostgreSQL 15
PostgreSQL 14 gacha har qanday foydalanuvchi public sxemada jadval yarata olardi (PUBLIC'da CREATE bor edi). Bu xavfli edi: huquqsiz foydalanuvchi public ga lower nomli funksiya yoki boshqa jadval nomini "ekib", boshqalarni aldashi mumkin edi — Funksiyalar va PL/pgSQL darsidagi search_path hujumining qarindoshi. PostgreSQL 15 dan public sxemada CREATE faqat baza egasida. Kanon baribir aniq yozgan — eski versiyadan ko'chirilgan bazada eski huquq qolgan bo'lishi mumkin:
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
GRANT USAGE, CREATE ON SCHEMA public TO vazifalar_migratsiya;
GRANT USAGE ON SCHEMA public TO vazifalar_hisobot;Natija nspacl da (sxemaning huquqlar ro'yxati):
SELECT nspname, nspacl FROM pg_namespace WHERE nspname = 'public'; nspname | nspacl
---------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
public | {pg_database_owner=UC/pg_database_owner,=U/pg_database_owner,vazifalar_ilova=U/pg_database_owner,vazifalar_migratsiya=UC/pg_database_owner,vazifalar_hisobot=U/pg_database_owner}
(1 row)O'qish: rol=huquqlar/kim_bergan. U — USAGE, C — CREATE. =U (rol nomisiz) — PUBLIC: faqat ko'rish. C faqat egasida va migratsiya rolida.
4. API roli amalda
SET ROLE bilan API bo'lamiz (session_user — haqiqiy ulangan, current_user — hozir kim nomidan ishlayapmiz). Chiqishda har buyruqning javobiga qarang: kundalik ish (o'qish, UPDATE) o'tadi, "xavfli" to'rt buyruq rad etiladi:
SET ROLE vazifalar_api;
SELECT current_user, session_user;
BEGIN;
SET LOCAL ilova.foydalanuvchi_id = '2';
SELECT count(*) AS dilnoza_vazifalari FROM vazifalar;
UPDATE vazifalar SET bajarildi = true,
bajarilgan_vaqt = '2026-10-24 12:00+05'
WHERE id = (SELECT min(id) FROM vazifalar WHERE NOT bajarildi)
RETURNING id;
ROLLBACK;
CREATE TABLE api_yaratdi (x int);
DROP TABLE izohlar;
TRUNCATE vazifalar;
SELECT count(*) FROM vazifa_tarixi;
RESET ROLE;SET
current_user | session_user
---------------+--------------
vazifalar_api | postgres
(1 row)
BEGIN
SET
dilnoza_vazifalari
--------------------
6
(1 row)
id
----
14
(1 row)
UPDATE 1
ROLLBACK
ERROR: permission denied for schema public
LINE 1: CREATE TABLE api_yaratdi (x int);
^
ERROR: must be owner of table izohlar
ERROR: permission denied for table vazifalar
ERROR: permission denied for table vazifa_tarixi
RESETNima bo'ldi?
| Buyruq | Natija | Sabab |
|---|---|---|
SELECT, UPDATE |
o'tdi | vazifalar_ilova dan meros DML |
CREATE TABLE |
rad | sxemada CREATE yo'q |
DROP TABLE |
rad | rol jadval egasi emas |
TRUNCATE, tarixni o'qish |
rad | huquq berilmagan |
- Kundalik ish — ishlaydi, RLS ostida (Dilnozaning 6 vazifasi).
CREATE TABLE— sxemadaCREATEyo'q.DROP TABLE— "must be owner": jadvalni faqat uning egasi o'chira oladi; bu huquqGRANTbilan berilmaydi.TRUNCATE— berilmagan.- Tarixni o'qish — faqat
INSERTberilgan.
Endi SQL injection bilan API'ni buzgan hujumchi ham shu cheklovlarda: jadvalni o'chira olmaydi, tarixni o'qiy olmaydi, begona foydalanuvchining qatorlarini ko'rmaydi (RLS).
5. Hisobot roli va SET ROLE tuzog'i
5.1 ALTER ROLE … SET
Kanon hisobot roliga ikki sozlama bergan:
ALTER ROLE vazifalar_hisobot SET statement_timeout = '30s';
ALTER ROLE vazifalar_hisobot SET default_transaction_read_only = on;statement_timeout — og'ir analitik so'rov 30 soniyadan keyin bekor bo'ladi va bazani band qilib qo'ymaydi. default_transaction_read_only — har tranzaksiya sukut bo'yicha faqat o'qish uchun.
5.2 SET ROLE sozlamalarni qo'llamaydi
Kanon topilmasi. SET ROLE bilan hisobot bo'lamiz va sozlamani tekshiramiz:
SET ROLE vazifalar_hisobot;
SHOW default_transaction_read_only;
SELECT count(*) AS hisobot_hammasini_koradi FROM vazifalar;
UPDATE vazifalar SET matn = 'x' WHERE id = 1;
RESET ROLE;SET
default_transaction_read_only
-------------------------------
off
(1 row)
hisobot_hammasini_koradi
--------------------------
48
(1 row)
ERROR: permission denied for table vazifalar
RESEToff! ALTER ROLE … SET sozlamalari faqat ulanish paytida (LOGIN) o'qiladi, SET ROLE da emas. UPDATE baribir to'xtadi — lekin GRANT yo'qligi sababli (permission denied), read-only sababli emas.
Haqiqiy ulanish bilan (psql'da \c - rol — shu bazaga boshqa rol bilan qayta ulanish; \set QUIET on faqat ulanish xabarini yashiradi):
\set QUIET on
\c - vazifalar_hisobot
\set QUIET off
SELECT current_user, session_user;
SHOW default_transaction_read_only;
SHOW statement_timeout;
UPDATE vazifalar SET matn = 'x' WHERE id = 1; current_user | session_user
-------------------+-------------------
vazifalar_hisobot | vazifalar_hisobot
(1 row)
default_transaction_read_only
-------------------------------
on
(1 row)
statement_timeout
-------------------
30s
(1 row)
ERROR: cannot execute UPDATE in a read-only transactionEndi sozlamalar ishladi, xato ham boshqa: "faqat o'qish tranzaksiyasida UPDATE bajarib bo'lmaydi". Ikki himoya qatlami: read-only sessiya va GRANT yo'q. Kanon pg_sleep(31) bilan timeout'ni ham ko'rgan: canceling statement due to statement timeout.
Saboq: rol sozlamalarini haqiqiy login bilan sinang; SET ROLE — huquqlarni tekshirish uchun, sozlamalarni emas.
5.3 Nega hisobotga BYPASSRLS
Hisobot "bugun nechta vazifa yaratildi (hammaniki)" kabi savollarga javob beradi — u hamma qatorni ko'rishi kerak. Ikki yo'l bor edi: hisobot uchun alohida siyosatlar yoki BYPASSRLS. Kanon ikkinchisini ongli tanlagan va migratsiya izohida yozgan. Narxi: bu rol sizsa — hamma ma'lumot ochiq. Shuning uchun u read-only, 5 ulanish, alohida parol va faqat ichki tarmoqdan.
Tekshirib ko'ring: Hisobot roli
default_transaction_read_only = onbilan ulandi. USET default_transaction_read_only = off;qilib, keyin UPDATE qila oladimi?
Javob
Sozlamani o'chira oladi — bu sessiya sozlamasi, foydalanuvchi o'zgartirishi mumkin. Lekin UPDATE baribir o'tmaydi: hisobot rolida jadvalga UPDATE huquqi (GRANT) yo'q. Shuning uchun read-only sozlama — qulaylik va xato oldini olish, haqiqiy himoya — GRANT. Ikkalasi birga.
6. Migratsiya roli va egalik
6.1 "must be owner"
Migratsiya roli jadval yaratadi, lekin postgres yaratgan jadvalni o'zgartira olmaydi:
SET ROLE vazifalar_migratsiya;
CREATE TABLE migratsiya_sinov (id int);
ALTER TABLE vazifalar ADD COLUMN x int;
SELECT grantee,
string_agg(privilege_type, ',' ORDER BY privilege_type)
FROM information_schema.role_table_grants
WHERE table_name = 'migratsiya_sinov'
AND grantee <> 'vazifalar_migratsiya'
GROUP BY 1 ORDER BY 1;
DROP TABLE migratsiya_sinov;
RESET ROLE;SET
CREATE TABLE
ERROR: must be owner of table vazifalar
grantee | string_agg
-------------------+-----------------------------
vazifalar_hisobot | SELECT
vazifalar_ilova | DELETE,INSERT,SELECT,UPDATE
(2 rows)
DROP TABLE
RESETALTER TABLE — faqat egasiga. Holat 11 da barcha jadvallar egasi — postgres (ularni 26-qismda superuser yaratgan). To'g'ri yechim: jadvallar egasi migratsiya roli bo'lsin (ALTER TABLE … OWNER TO vazifalar_migratsiya yoki bazani boshidan shu rol bilan qurish). Kanon buni keyingi bosqichga — migratsiya vositasi darslariga (Prisma Migrate chuqur) qoldirgan.
6.2 ALTER DEFAULT PRIVILEGES — kelajak uchun
Ikkinchi natijaga qarang: yangi migratsiya_sinov jadvali o'zi huquqlarni oldi — hech kim GRANT yozmadi. Bu default privileges:
ALTER DEFAULT PRIVILEGES FOR ROLE vazifalar_migratsiya
IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO vazifalar_ilova;
ALTER DEFAULT PRIVILEGES FOR ROLE vazifalar_migratsiya
IN SCHEMA public GRANT USAGE ON SEQUENCES TO vazifalar_ilova;
ALTER DEFAULT PRIVILEGES FOR ROLE vazifalar_migratsiya
IN SCHEMA public GRANT SELECT ON TABLES TO vazifalar_hisobot;"vazifalar_migratsiya kelajakda public da yaratadigan har jadvalga — avtomatik shu huquqlar". GRANT … ON ALL TABLES esa faqat hozir mavjud jadvallarga ta'sir qiladi. Ikkalasi kerak: biri o'tmish uchun, biri kelajak uchun. Unutilsa — har yangi migratsiyadan keyin API permission denied for table … bilan to'xtaydi (va bu odatda prod'da birinchi bo'lib ko'rinadi).
FOR ROLE muhim: default privileges faqat ko'rsatilgan rol yaratgan obyektlarga ishlaydi. Boshqa rol yaratgan jadval huquqsiz qoladi.
6.3 Kanon xatosi va "qo'llangan migratsiya o'zgarmaydi" qoidasi
Kanonning 106 faylidagi uchta qator dastlab FOR ROLE postgres bilan yozilgan edi. 27-qism oxiridagi Testcontainers testlari (Testcontainers darsida; sinov konteynerida superuser nomi test) xatoni topdi: role "postgres" does not exist — migratsiya superuser nomi boshqa bo'lgan har serverda (masalan, managed bazada) yiqilardi. Tuzatish — FOR ROLE CURRENT_USER ("migratsiyani bajarayotgan rol"):
ALTER DEFAULT PRIVILEGES FOR ROLE CURRENT_USER IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO vazifalar_ilova;Qoida bor edi: qo'llangan migratsiya fayli o'zgartirilmaydi — o'zgarish yangi fayl bilan. Bu yerda istisno qilindi va bu bosh muharrir qarori bilan qabul qilindi. Sabab: yangi bazada eski 106 baribir role "postgres" does not exist da yiqiladi — keyingi "tuzatuvchi" fayl unga yetib bormaydi. Kurs hali nashr qilinmagan, ya'ni hech qayerda eski 106 qo'llanmagan. Real loyihada (fayl prod'da qo'llangan bo'lsa) bunday istisno bo'lmaydi — u holda yangi migratsiya va eski bazalar uchun alohida tuzatish yo'li tanlanadi (Migratsiya tushunchasi darsida).
7. Yana bir topilma: REVOKE CONNECT faqat bitta bazada
Kanon haqiqiy login bilan tekshirgan: vazifalar_api boshqa bazalarga ham ulana oldi. Biz o'z klasterimizda takrorladik — h07 — boshqa holat bazasi, 106 u yerda qo'llanmagan:
psql -h 127.0.0.1 -p 5552 -U vazifalar_api -d h07 -c "SELECT 1" ?column?
----------
1
(1 row)Sabab: REVOKE CONNECT … FROM PUBLIC faqat vazifalar bazasida qilingan. Boshqa bazalarda PUBLIC'ning sukut CONNECT huquqi qoldi, rollar esa klaster bo'ylab umumiy. Yechimlar: har bazada REVOKE CONNECT … FROM PUBLIC, va asosiysi — pg_hba.conf da "qaysi rol qaysi bazaga qayerdan ulanadi" qoidasi (Postgres arxitekturasi va asosiy sozlamalar darsida).
8. Parollar haqida
Kanon (va bizning lokal klaster) trust rejimida — parolsiz. Bu faqat lokal tajriba uchun. Serverda:
-- serverda, migratsiyada EMAS — parol fayl tarixiga tushadi
CREATE ROLE vazifalar_api LOGIN PASSWORD '…' IN ROLE vazifalar_ilova;- Parol hech qachon migratsiya fayliga yoki git'ga yozilmaydi — u
.envda yoki sirlar xizmatida. Rolni migratsiya yaratadi, parolni administrator alohida qo'yadi (ALTER ROLE … PASSWORD, psql'dagi\password— u parolni terminalda yashiradi va log'ga ochiq yozmaydi). - Saqlash algoritmi —
scram-sha-256(PostgreSQL 14 dan sukut); eskimd5— ishlatmang. DATABASE_URLda har xizmat o'z roli bilan: API —vazifalar_api, migratsiya —vazifalar_migratsiya. Bu kursda parolli ulanish sinalmagan (trust); tafsilot — hujjatda.
9. Ko'p uchraydigan xatolar
9.1 Ilova superuser bilan ulangan
RLS ishlamaydi, SQL injection — butun server. Ilova — LOGIN rol, guruh a'zosi, faqat DML.
9.2 GRANT … ON ALL TABLES dan keyin yangi jadval huquqsiz
permission denied for table … faqat yangi jadvalda. ALTER DEFAULT PRIVILEGES FOR ROLE <jadval yaratuvchi>.
9.3 SET ROLE bilan sozlamani tekshirish
ALTER ROLE … SET ko'rinmaydi. Haqiqiy login (psql -U, \c - rol).
9.4 Sequence'ni unutish
INSERT da permission denied for sequence … (identity ustun ham sequence ishlatadi). GRANT USAGE ON SEQUENCES (yoki default privileges'da).
9.5 Migratsiya va ilova bitta rol
Ilova jadvalni o'chira oladi. Ikki rol; ilova jadval egasi emas.
10. Mashqlar
Mashqlar o'z rollaringiz bilan. Rollar klaster darajasida — oxirida o'chiring (DROP OWNED BY rolning huquqlari va obyektlarini tozalaydi).
1-mashq (oson): Faqat o'qiydigan rol
m11_menyu (nom text, narx int) jadvalini yarating. Unga osh (35 000) va manti (30 000) ni qo'shing. m11_oquvchi rolini yarating. Unga faqat SELECT bering. SET ROLE bilan: menyuni o'qing (narxlar yig'indisi), keyin UPDATE ga urining — xatoni ushlash uchun Funksiyalar va PL/pgSQL darsidagi kabi EXCEPTION WHEN insufficient_privilege li yordamchi funksiya yozing.
Yechim
CREATE ROLE m11_oquvchi;
CREATE TABLE m11_menyu (nom text, narx int);
INSERT INTO m11_menyu VALUES ('osh', 35000), ('manti', 30000);
GRANT SELECT ON m11_menyu TO m11_oquvchi;
CREATE FUNCTION m11_urin() RETURNS text LANGUAGE plpgsql AS $$
BEGIN
UPDATE m11_menyu SET narx = 0;
RETURN 'o''zgardi';
EXCEPTION WHEN insufficient_privilege THEN
RETURN 'rad: ' || SQLERRM;
END $$;
SET ROLE m11_oquvchi;
SELECT 'jami: ' || sum(narx) FROM m11_menyu;
SELECT m11_urin();
RESET ROLE;
DROP FUNCTION m11_urin;
DROP TABLE m11_menyu;
DROP ROLE m11_oquvchi;Biz ishga tushirdik (psql -X -q -A -t, PostgreSQL 17.6):
jami: 65000
rad: permission denied for table m11_menyuFunksiya SECURITY DEFINER emas — chaqiruvchi (m11_oquvchi) huquqi bilan ishladi, shuning uchun UPDATE rad etildi.
2-mashq (o'rta): Guruh va a'zo
m11_kassa guruhini (NOLOGIN) yarating, unga m11_buyurtma (id int GENERATED ALWAYS AS IDENTITY, taom text) jadvaliga SELECT, INSERT va sequence'ga USAGE bering. m11_kassir (LOGIN IN ROLE m11_kassa) — o'zida huquq yo'q. SET ROLE m11_kassir bilan buyurtma qo'shing va soni chiqaring. Keyin a'zolikni olib tashlang (REVOKE m11_kassa FROM m11_kassir) va has_table_privilege('m11_kassir', 'm11_buyurtma', 'INSERT') ni chiqaring.
Yechim
CREATE ROLE m11_kassa NOLOGIN;
CREATE ROLE m11_kassir LOGIN IN ROLE m11_kassa;
CREATE TABLE m11_buyurtma (
id int GENERATED ALWAYS AS IDENTITY, taom text);
GRANT SELECT, INSERT ON m11_buyurtma TO m11_kassa;
GRANT USAGE ON SEQUENCE m11_buyurtma_id_seq TO m11_kassa;
SET ROLE m11_kassir;
INSERT INTO m11_buyurtma (taom) VALUES ('osh'), ('lag''mon');
SELECT 'buyurtmalar: ' || count(*) FROM m11_buyurtma;
RESET ROLE;
REVOKE m11_kassa FROM m11_kassir;
SELECT 'insert huquqi: '
|| has_table_privilege('m11_kassir', 'm11_buyurtma', 'INSERT');
DROP TABLE m11_buyurtma;
DROP ROLE m11_kassir;
DROP ROLE m11_kassa;Biz ishga tushirdik (psql -X -q -A -t, PostgreSQL 17.6):
buyurtmalar: 2
insert huquqi: falseKassir huquqni guruhdan meros oldi; a'zolik olingach — huquq ham ketdi. Xodim ishdan ketsa — bitta REVOKE (yoki DROP ROLE), jadvallarni birma-bir aylanish shart emas.
3-mashq (qiyin): Default privileges
m11_mig (jadval yaratuvchi) va m11_app rollarini yarating. m11_mig ga public sxemada CREATE bering va ALTER DEFAULT PRIVILEGES FOR ROLE m11_mig IN SCHEMA public GRANT SELECT ON TABLES TO m11_app qiling. Keyin: (1) SET ROLE m11_mig bilan m11_a jadvalini yarating; (2) superuser sifatida m11_b ni yarating. Ikkala jadval uchun m11_app ning SELECT huquqini chiqaring. Tushuntiring. Tozalash: DROP OWNED BY har rol uchun alohida, keyin DROP ROLE.
Yechim
CREATE ROLE m11_mig;
CREATE ROLE m11_app;
GRANT USAGE, CREATE ON SCHEMA public TO m11_mig;
ALTER DEFAULT PRIVILEGES FOR ROLE m11_mig IN SCHEMA public
GRANT SELECT ON TABLES TO m11_app;
SET ROLE m11_mig;
CREATE TABLE m11_a (x int);
RESET ROLE;
CREATE TABLE m11_b (x int);
SELECT t || ': ' || has_table_privilege('m11_app', t, 'SELECT')
FROM unnest(ARRAY['m11_a', 'm11_b']) AS t;
DROP TABLE m11_b;
DROP OWNED BY m11_mig;
DROP OWNED BY m11_app;
DROP ROLE m11_mig;
DROP ROLE m11_app;Biz ishga tushirdik (psql -X -q -A -t, PostgreSQL 17.6):
m11_a: true
m11_b: falseDefault privileges faqat m11_mig yaratgan jadvalga ishladi. Superuser yaratgan m11_b huquqsiz qoldi — shuning uchun hamma migratsiya bitta rol (migratsiya roli) bilan bajarilishi kerak. DROP OWNED BY — rolga tegishli obyektlarni (m11_a) va unga berilgan huquqlarni (sxemadagi CREATE, default privileges) o'chiradi; usiz DROP ROLE role … cannot be dropped because some objects depend on it beradi. Ikki rolni bitta buyruqda (DROP OWNED BY m11_mig, m11_app) tozalashga urinsak, PostgreSQL 17.6 da could not find tuple for default ACL … xatosini oldik (default privileges ikkala rolga bog'liq bo'lgani uchun) — alohida-alohida chaqirish ishladi.
11. Loyiha qadami: rollar migratsiyasi (holat 11)
Holat 09 → holat 11. Bitta fayl — sql/106-rollar.sql. Bu — P bosqichning (Postgres chuqur) yakuniy sxemasi. Kanon fayli to'liq; uzun qatorlar va izohlar telefon uchun bo'lindi, mazmuni aynan:
-- 106-rollar.sql — 27-qism #11 (DB-72, holat 11): rollar va huquqlar
-- — eng kam huquq tamoyili.
-- vazifalar_migratsiya — sxemani o'zgartiradi (DDL), jadvallar
-- egasi bo'la oladi; ilova u bilan ISHLAMAYDI
-- vazifalar_ilova — guruh (NOLOGIN, 105): faqat DML, RLS ostida
-- vazifalar_api — LOGIN, vazifalar_ilova a'zosi (API jarayoni
-- shu bilan ulanadi)
-- vazifalar_hisobot — LOGIN, faqat o'qish (analitika, BI). RLS'ni
-- chetlab o'tishi kerak — BYPASSRLS (ongli qaror, izohda)
-- Parollar: lokal kanon konteyneri trust (parolsiz). Serverda:
-- CREATE ROLE … PASSWORD '…' (scram-sha-256) — sir .env da, bu faylda
-- EMAS.
DO $$ BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_roles
WHERE rolname = 'vazifalar_migratsiya') THEN
CREATE ROLE vazifalar_migratsiya LOGIN; END IF;
IF NOT EXISTS (SELECT 1 FROM pg_roles
WHERE rolname = 'vazifalar_api') THEN
CREATE ROLE vazifalar_api LOGIN IN ROLE vazifalar_ilova; END IF;
IF NOT EXISTS (SELECT 1 FROM pg_roles
WHERE rolname = 'vazifalar_hisobot') THEN
CREATE ROLE vazifalar_hisobot LOGIN BYPASSRLS; END IF;
END $$;
-- Ulanish limiti: bitta rol butun max_connections'ni egallab olmasin
ALTER ROLE vazifalar_api CONNECTION LIMIT 40;
ALTER ROLE vazifalar_hisobot CONNECTION LIMIT 5;
-- Hisobot roli: uzun so'rov ilovani to'xtatmasin
ALTER ROLE vazifalar_hisobot SET statement_timeout = '30s';
ALTER ROLE vazifalar_hisobot SET default_transaction_read_only = on;
-- Bazaga ulanish: PUBLIC dan olib, aniq rollarga
-- baza nomi qat'iy yozilmaydi (holat boshqa nom bilan qurilishi
-- mumkin — tekshir.sh "tekshiruv" bazasi)
DO $$ BEGIN
EXECUTE format(
'REVOKE CONNECT, TEMPORARY ON DATABASE %I FROM PUBLIC',
current_database());
EXECUTE format(
'GRANT CONNECT ON DATABASE %I TO vazifalar_migratsiya, '
|| 'vazifalar_api, vazifalar_hisobot',
current_database());
END $$;
-- Sxema: PG 15+ da public sxemaga CREATE PUBLIC'da yo'q (eski
-- versiyalarda bor edi — aniq yozamiz)
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
GRANT USAGE, CREATE ON SCHEMA public TO vazifalar_migratsiya;
GRANT USAGE ON SCHEMA public TO vazifalar_hisobot;
-- Hisobot: hamma jadval va view'ni o'qish (yozish yo'q)
GRANT SELECT ON ALL TABLES IN SCHEMA public TO vazifalar_hisobot;
-- Kelajakdagi jadvallar (migratsiyani bajarayotgan rol —
-- CURRENT_USER —
-- yoki migratsiya roli yaratganda) huquqlarni o'zi oladi.
-- KANON XATOSI TUZATILDI (27 holat 65, Testcontainers topdi): avval
-- "FOR ROLE postgres" edi — superuser boshqa nomli serverda
-- (Testcontainers "test", managed DB) migratsiya
-- `role "postgres" does
-- not exist` bilan yiqilardi.
ALTER DEFAULT PRIVILEGES FOR ROLE CURRENT_USER IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO vazifalar_ilova;
ALTER DEFAULT PRIVILEGES FOR ROLE CURRENT_USER IN SCHEMA public
GRANT USAGE ON SEQUENCES TO vazifalar_ilova;
ALTER DEFAULT PRIVILEGES FOR ROLE CURRENT_USER IN SCHEMA public
GRANT SELECT ON TABLES TO vazifalar_hisobot;
ALTER DEFAULT PRIVILEGES FOR ROLE vazifalar_migratsiya
IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO vazifalar_ilova;
ALTER DEFAULT PRIVILEGES FOR ROLE vazifalar_migratsiya
IN SCHEMA public
GRANT USAGE ON SEQUENCES TO vazifalar_ilova;
ALTER DEFAULT PRIVILEGES FOR ROLE vazifalar_migratsiya
IN SCHEMA public
GRANT SELECT ON TABLES TO vazifalar_hisobot;
-- Funksiyalar: PUBLIC'da EXECUTE sukut bo'yicha bor — qoldiramiz
-- (trigger funksiyalari, uz_normal, joriy_foydalanuvchi kerak)Oxirgi izohga e'tibor bering: funksiyalardagi PUBLIC EXECUTE ongli qoldirilgan — loyihada SECURITY DEFINER funksiya yo'q, qolganlari chaqiruvchi huquqi bilan ishlaydi va hech narsani "ochmaydi".
Commit:
git add sql/106-rollar.sql
M="db: rollar — migratsiya, api (ilova a'zosi), hisobot (read-only);"
M+=" default privileges (106)"
git commit -m "$M"Halol eslatma: rollar tayyor, lekin vazifalar-api hali postgres bilan ulanadi — DATABASE_URL ni vazifalar_api ga almashtirish API'ning har so'rovda set_config qilishini talab qiladi (Row Level Security darsidagi naqsh), "kim kirgan" esa 28-qismdagi autentifikatsiyadan keladi. Jadval egaligi (must be owner) — migratsiya vositasi darslarida.
12. Real ishda
- Har prod bazada kamida ikki rol: migratsiya va ilova. Xavfsizlik auditida birinchi tekshiriladigan narsa — "ilova superuser bilan ulanmaydimi?".
- Analitika va BI (Metabase, Superset kabi) — alohida read-only rol, ko'pincha replika bazaga (asosiy bazaning faqat o'qiladigan nusxasiga) ulanadi.
- Managed bazalarda haqiqiy superuser umuman berilmaydi — provayderning "admin" roli bor; default privileges va egalik masalalari aynan shu yerda ko'p chiqadi (kanon xatosi — misol).
- Intervyu: "Least privilege'ni bazada qanday qo'llaysiz?", "Yangi jadval qo'shilganda ilova huquqni qanday oladi?".
Xulosa
- Rol — foydalanuvchi ham, guruh ham;
LOGINvaNOLOGINfarqi; a'zolik huquqni meros qiladi (rolinherit). - Huquq uch qavatda: baza (
CONNECT), sxema (USAGE,CREATE), obyekt (SELECT…); PUBLIC — "hamma". - PG 15+ da
publicsxemadaCREATEfaqat egasida;REVOKE CONNECTfaqat o'sha bazaga ta'sir qiladi. GRANT … ON ALL TABLES— hozirgilar uchun,ALTER DEFAULT PRIVILEGES FOR ROLE …— kelajakdagilar uchun.ALTER ROLE … SETfaqat haqiqiy login'da ishlaydi,SET ROLEda emas.DROP/ALTER— faqat egasi; migratsiya roli jadvallar egasi bo'lishi kerak.
Keyingi dars: Postgres arxitekturasi va asosiy sozlamalar — process-per-connection, shared_buffers, work_mem, WAL, pg_hba.conf va ALTER SYSTEM.
Manbalar
- PostgreSQL 18 hujjati: Database Roles, Role Membership — 2026-10-25 da ko'rildi.
- PostgreSQL 18 hujjati: Privileges, ALTER DEFAULT PRIVILEGES.
- PostgreSQL 15 reliz eslatmalari: Release 15 — public schema CREATE.
- PostgreSQL 18 hujjati: Password Authentication (
scram-sha-256).
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!