Row-Level Security (RLS) เป็นหนึ่งในฟีเจอร์สำคัญของ PostgreSQL ที่ช่วยให้ระบบสามารถควบคุมการเข้าถึงข้อมูล ระดับแถว ได้อย่างปลอดภัย โดยเฉพาะระบบที่มีผู้ใช้หลายกลุ่ม เช่น โรงพยาบาล, องค์กร, หรือ Multi-tenant application
บทความนี้จะอธิบาย
- RLS คืออะไร
- สิทธิของ superuser / owner ส่งผลยังไง
- ตัวอย่างผลลัพธ์ “ก่อน” และ “หลัง” ใช้ RLS
📌 Row-Level Security (RLS) คืออะไร?
RLS = การกรองข้อมูลระดับแถวโดยอัตโนมัติ ตามสิทธิของ user
PostgreSQL จะตรวจสอบทุกคำสั่ง SELECT, UPDATE, DELETE, INSERT
แล้วแสดงเฉพาะแถวที่ผ่าน policy ที่เรากำหนดไว้ เช่น:
- เห็นเฉพาะข้อมูลของโรงพยาบาลตนเอง
- เห็นเฉพาะข้อมูลที่ active
- ห้ามแก้ไขข้อมูลที่ถูกซ่อน
- ห้ามลบข้อมูลที่ไม่ใช่เจ้าของ
สามารถคิดง่ายๆ ว่า เป็นเหมือน WHERE อัตโนมัติที่ซ่อนอยู่ในระบบ
และ PostgreSQL จะใช้มันเองเสมอเมื่อมีการ Query
📌 สิทธิที่เกี่ยวข้องกับ RLS
✔ 1. Superuser
- ไม่ถูกบังคับด้วย RLS
- มองเห็นทุกเรคคอร์ดเหมือนปิด RLS อยู่
- ไม่ต้องมี policy ก็เห็นทุกข้อมูล
superuser = bypass RLS
✔ 2. Owner ของ table
ค่าเริ่มต้น owner ก็ ไม่โดน RLS เช่นกัน
- owner = select ได้ทุกแถว
- owner = update/delete ได้ทุกแถว
- แม้เปิด RLS แล้วก็ตาม
ถ้าอยากให้ owner ต้องทำตาม policy ต้องใช้:
ALTER TABLE your_table FORCE ROW LEVEL SECURITY;
หลังจากใช้ FORCE:
- owner ต้องทำตาม policy เช่นเดียวกับ user คนอื่น
- ยกเว้น superuser ที่ยัง bypass อยู่
✔ 3. User ปกติ (non-owner)
เป็นกลุ่มที่ RLS จะมีผลจริง
- ถ้าเปิด RLS แต่ไม่มี policy → เห็น 0 rows
- ถ้ามี policy → เห็นเฉพาะข้อมูลที่ตรง policy
📌 วิธีเปิด / ปิด RLS
เปิด RLS:
ALTER TABLE t_order ENABLE ROW LEVEL SECURITY;
ปิด RLS:
ALTER TABLE t_order DISABLE ROW LEVEL SECURITY;
📘 ตัวอย่างเข้าใจง่ายที่สุด
สมมติเรามี table:
CREATE TABLE t_order (
id SERIAL PRIMARY KEY,
hospital_code TEXT,
patient_name TEXT
);
INSERT INTO t_order (hospital_code, patient_name) VALUES
('A', 'Alice'),
('A', 'Amy'),
('B', 'Bob'),
('C', 'Chris');
User ที่เข้าถึงระบบ:
-
userA→ โรงพยาบาล A -
userB→ โรงพยาบาล B
🟦 ก่อนเปิด RLS (ไม่ใช้ RLS)
ผู้ใช้ทั้งสองเห็นเหมือนกันหมด
userA:
SELECT * FROM t_order;
ผลลัพธ์:
| id | hospital_code | patient_name |
|---|---|---|
| 1 | A | Alice |
| 2 | A | Amy |
| 3 | B | Bob |
| 4 | C | Chris |
userB:
ได้ผลเหมือนกันทุกอย่าง
➡ ทุกคนเห็นทุกข้อมูล
🟩 เปิดใช้งาน RLS
เปิด RLS:
ALTER TABLE t_order ENABLE ROW LEVEL SECURITY;
สร้าง policy จำกัดให้เห็นเฉพาะโรงพยาบาลของตน:
CREATE POLICY order_filter ON t_order
FOR SELECT
USING (hospital_code = current_setting('myapp.hospital_code'));
ก่อนสั่ง query ให้ตั้งค่าตาม user
🔍 ผลลัพธ์เมื่อเปิด RLS
👉 userA:
SET myapp.hospital_code = 'A';
SELECT * FROM t_order;
ผลลัพธ์:
| id | hospital_code | patient_name |
|---|---|---|
| 1 | A | Alice |
| 2 | A | Amy |
👉 userB:
SET myapp.hospital_code = 'B';
SELECT * FROM t_order;
ผลลัพธ์:
| id | hospital_code | patient_name |
|---|---|---|
| 3 | B | Bob |
🔥 สรุปผลลัพธ์แบบเทียบกันชัดๆ
❌ ไม่ใช้ RLS
| User | ข้อมูลที่เห็น |
|---|---|
| userA | ทุกแถว |
| userB | ทุกแถว |
✅ ใช้ RLS
| User | ข้อมูลที่เห็น |
|---|---|
| userA | เฉพาะโรงพยาบาล A |
| userB | เฉพาะโรงพยาบาล B |
⚠ หมายเหตุสำคัญ
หากเปิด RLS แต่ ไม่มี policy
ผู้ใช้ปกติจะเหมือนว่า table ว่างทันที:
SELECT * FROM t_order;
ผล:
0 rows
แต่ superuser และ owner ยังเห็นได้ (ถ้าไม่ FORCE)
📌 สรุปทั้งหมด
- RLS คือฟีเจอร์ควบคุมการเห็นข้อมูลระดับแถว
- Superuser และ Owner (โดย default) จะ bypass RLS
- User ปกติจะถูกบังคับใช้ RLS
- เปิด RLS แล้ว ต้องมี policy ไม่งั้นเห็น 0 rows
- ใช้ RLS เพื่อทำระบบ multi-tenant หรือแบ่งสิทธิข้อมูลได้อย่างปลอดภัยมาก
Top comments (0)