SaaS · PostgreSQL

عزل بيانات العملاء في PostgreSQL باستخدام RLS

كيف تصمّم عزل بيانات العملاء في SaaS باستخدام PostgreSQL RLS، وتضبط سياق العميل والصلاحيات وتختبر منع تسرّب البيانات.

المسار المرتبطالسحابة وDevOps وKubernetes
مساحات منفصلة داخل بنية مشتركة، لتوضيح عزل بيانات العملاء.
تصوّر بصري للفكرة — يتبعه شرح ومخطط تنفيذي داخل المقال.

في تطبيق SaaS، قد يبدأ عزل العملاء بشرط tenant_id داخل الاستعلام. المشكلة أن التقرير الجديد أو المهمة الخلفية قد ينسى هذا الشرط. العزل الجيد يحتاج إلى أكثر من اتفاق بين المطوّرين: نريد طبقة تمنع الوصول غير المسموح به، واختبارات تثبت أن كل مسار يستخدمها فعلًا. هذا المقال يقترح تصميمًا لقاعدة مشتركة؛ وليس وصفًا لنظام جاهز يمكن نسخه دون مراجعة.

متى تكون القاعدة المشتركة مناسبة؟

عندما تتشابه بنية بيانات العملاء ويكون التشغيل المركزي مهمًا، قد تكون الجداول المشتركة خيارًا عمليًا. لكنها تجعل حدود العميل جزءًا من تصميم كل جدول وعلاقة وفهرس. قاعدة مستقلة لكل عميل تمنح خيارات تشغيل وعزل مختلفة، مقابل تعقيد الترحيلات والنسخ الاحتياطي والاتصالات. اختَر وفق احتياج المنتج ومتطلبات العملاء، لا وفق عدد العملاء وحده.

ما الذي تفعله RLS؟

بعد تفعيل Row-Level Security، تحدّد السياسات الصفوف التي يستطيع دور قاعدة البيانات قراءتها أو تعديلها. غياب سياسة مناسبة يعني المنع الافتراضي للأدوار التي تخضع لـRLS. لكن المالك والأدوار ذات BYPASSRLS والمستخدم الفائق حالات مهمة؛ تشغيل التطبيق بدور ذي امتيازات واسعة قد يلغي الحماية المتوقعة.

مرّر سياق العميل ضمن المعاملة

استخرج العميل من جلسة موثوقة واربطه بعضوية المستخدم، ثم اضبط السياق داخل معاملة قصيرة. لا تثق بقيمة يرسلها المتصفح لمجرد أنها تسمّى tenant_id. في connection pooling، السياق المستمر على اتصال قديم خطر؛ لذلك استخدم إعدادًا محليًا للمعاملة. المثال التالي توضيحي ويحتاج أدوارًا وسياسات مدروسة قبل الإنتاج.

ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
ALTER TABLE invoices FORCE ROW LEVEL SECURITY;
CREATE POLICY invoice_tenant ON invoices
USING (tenant_id = nullif(current_setting('app.tenant_id', true), '')::uuid)
WITH CHECK (tenant_id = nullif(current_setting('app.tenant_id', true), '')::uuid);
BEGIN;
SELECT set_config('app.tenant_id', :trusted_tenant_id, true);
SELECT id, total FROM invoices ORDER BY id LIMIT 20;
COMMIT;
التحقّق من الهوية والعضوية يسبق الوصول إلى البيانات ضمن سياق العميل.
التحقّق من الهوية والعضوية يسبق الوصول إلى البيانات ضمن سياق العميل. اضغط لعرض أكبر

الحدود لا تنتهي عند SQL

تخيّل أن طلبًا صحيحًا يقرأ فاتورة ثم يخزّنها في Redis بمفتاح invoice:42. إذا تكرّر الرقم بين العملاء، قد يخرج الرد من الكاش قبل الوصول إلى PostgreSQL. استخدم مفاتيح تشمل العميل، واحمل هويته إلى المهام الخلفية ومسارات الملفات. افحص أيضًا علاقات الجداول: وجود tenant_id في الفاتورة لا يضمن أن customer_id يشير إلى عميل من نفس المؤسسة. يمكن تصميم قيود مركّبة لتثبيت هذه العلاقة.

اختبر الفشل قبل النجاح

أنشئ عميلين وبيانات مختلفة، وشغّل الاختبارات بدور التطبيق الفعلي. جرّب القراءة والتحديث والحذف والإدخال بمعرّفات العميل الآخر. اختبر غياب السياق، والتنقّل بين عميلين على اتصالات معاد استخدامها، ومهام التقارير والتصدير. اختبر مسار الإدارة على حدة، بصلاحيات صريحة وسجل تدقيق. نجاح صفحة القائمة لا يثبت سلامة بقية النظام.

قرار تنفيذي

ابدأ بجرد مسارات البيانات، ثم طبّق السياسة على جدول واحد واختبرها مع الدور الحقيقي والـpool المستخدم. وثّق الاستثناءات قبل التوسّع. RLS طبقة قوية ضمن التصميم، لكنها لا تعالج تلقائيًا التخزين المؤقت أو الملفات أو التحقّق من عضوية المستخدم.

سيناريو عملي: تصدير فواتير عميل

افترض أن مديرًا طلب تصدير الفواتير، ثم خرج من حسابه قبل تشغيل المهمة. لا تربط التنفيذ بجلسة المتصفح التي قد تنتهي؛ احفظ هوية العميل والجهة التي طلبت العملية، ثم تحقّق من سياسة التفويض المناسبة عند تشغيلها. يجب أن تفتح المهمة معاملة بسياق العميل، وأن تكتب الملف في مساحة تخصّه. عند التنزيل، أعد التحقّق من صلاحية المستخدم بدل الاعتماد على أن الرابط أُنشئ في وقت سابق لشخص مخوّل.

مراجعة قبل الإطلاق

جرّب سحب صلاحية الموظف بين إنشاء التصدير وتنزيله، وتغيير العميل أثناء إعادة استخدام الاتصال، وتشغيل مهمتين لعميلين مختلفين في الوقت نفسه. راقب النتيجة الفعلية، لا قيمة tenant_id في السجل فقط. احتفظ باختبار يكشف أي صف من العميل الآخر، وباختبار يمنع تقديم الملف بعد انتهاء الصلاحية. إن احتاج الدعم وصولًا استثنائيًا، اجعله مسارًا مسجّلًا ومحدودًا بدل تعطيل الحماية العامة.

المراجع الرسمية

تدعم هذه المراجع سلوك الأدوات المذكورة. الأمثلة وقرارات التصميم توضيحية، ويجب تكييفها مع متطلبات المشروع وإصداراته.

إعداد: Noor Yasser

من القرار إلى التنفيذ

تعمل على تحدٍ تقني مشابه؟

أساعد الفرق على تحويل القرار المعماري إلى نطاق واضح وتنفيذ يمكن تشغيله ومراجعته بثقة.

احجز لقاءً لمدة ٣٠ دقيقةالخدمة المرتبطةتطوير منصات SaaS والمنتجات الرقميةمشروع من الأعمالمُرشد