36. أمان PostgreSQL¶
يمتلك PostgreSQL نظام صلاحيات غنيًا ومرنًا، مع القدرة على توزيع صلاحيات معينة على أدوار محددة (roles)، ومنح المستخدمين صلاحيات دور واحد أو أكثر من تلك الأدوار (roles).
إضافة إلى ذلك، يمكن لخادم PostgreSQL استخدام أنظمة متعددة مختلفة للتحقق من هوية المستخدمين. وهذا يعني أن قاعدة البيانات يمكنها استخدام البنية التحتية نفسها للتحقق من الهوية التي تستخدمها مكونات المعمارية الأخرى، مما يبسّط إدارة كلمات المرور.
36.1. المستخدمون والأدوار¶
سننشئ في هذا الفصل مستخدمَين مفيدَين لبيئة الإنتاج:
مستخدم للقراءة فقط لاستخدامه في تطبيق نشر.
مستخدم للقراءة والكتابة يستخدمه مطوّر في بناء برمجيات أو تحليل بيانات.
بدلًا من إنشاء المستخدمين ومنحهم الصلاحيات اللازمة، سننشئ دورين بالصلاحيات المناسبة، ثم ننشئ مستخدمَين ونضيفهما إلى الدورين المناسبين. وبهذه الطريقة يمكننا إعادة استخدام الأدوار بسهولة عند إنشاء مستخدمين آخرين.
36.1.1. إنشاء الأدوار¶
الدور مستخدم والمستخدم دور. والفرق الوحيد هو أنه يمكن القول إن "المستخدم" دور يملك صلاحية "تسجيل الدخول" (login).
لذا من الناحية الوظيفية، تعليمتا SQL أدناه متطابقتان؛ فكلتاهما تنشئ "دورًا بصلاحية تسجيل الدخول"، أي "مستخدمًا".
CREATE ROLE mrbean LOGIN;
CREATE USER mrbean;
36.1.2. مستخدمو القراءة فقط¶
سيكون مستخدم القراءة فقط لدينا مخصصًا لتطبيق ويب يستخدمه للاستعلام عن الجدول nyc_streets.
سيكون للتطبيق وصول محدد إلى الجدول nyc_streets، لكنه سيرث صلاحيات النظام اللازمة لعمليات PostGIS من الدور postgis_reader.
-- A user account for the web app
CREATE USER app1;
-- Web app needs access to specific data tables
GRANT SELECT ON nyc_streets TO app1;
-- A generic role for access to PostGIS functionality
CREATE ROLE postgis_reader INHERIT;
-- Give that role to the web app
GRANT postgis_reader TO app1;
الآن، عندما نسجّل الدخول باسم app1، يمكننا تحديد صفوف من الجدول nyc_streets. لكن لا يمكننا تنفيذ استدعاء ST_Transform! لماذا؟
-- This works!
SELECT * FROM nyc_streets LIMIT 1;
-- This doesn't work!
SELECT ST_AsText(ST_Transform(geom, 4326))
FROM nyc_streets LIMIT 1;
ERROR: permission denied for relation spatial_ref_sys
CONTEXT: SQL statement "SELECT proj4text FROM spatial_ref_sys WHERE srid = 4326 LIMIT 1"
الإجابة موجودة في رسالة الخطأ. فرغم أن المستخدم app1 يستطيع عرض محتويات الجدول nyc_streets دون مشكلة، فإنه لا يستطيع عرض محتويات spatial_ref_sys، لذا يفشل استدعاء ST_Transform.
لذا نحتاج أيضًا إلى منح الدور postgis_reader صلاحية القراءة لجميع جداول البيانات الوصفية في PostGIS:
GRANT SELECT ON geometry_columns TO postgis_reader;
GRANT SELECT ON geography_columns TO postgis_reader;
GRANT SELECT ON spatial_ref_sys TO postgis_reader;
أصبح لدينا الآن دور عام ومفيد هو postgis_reader يمكننا تطبيقه على أي مستخدم يحتاج إلى القراءة من جداول PostGIS.
-- This works now!
SELECT ST_AsText(ST_Transform(geom, 4326))
FROM nyc_streets LIMIT 1;
36.1.3. مستخدمو القراءة والكتابة¶
هناك نوعان من سيناريوهات القراءة والكتابة علينا أخذهما في الاعتبار:
تطبيقات الويب وغيرها التي تحتاج إلى الكتابة في جداول بيانات موجودة.
المطورون أو المحللون الذين يحتاجون إلى إنشاء جداول وأعمدة أشكال هندسية جديدة ضمن عملهم.
بالنسبة لتطبيقات الويب التي تتطلب صلاحية الكتابة في جداول البيانات، نحتاج فقط إلى منح صلاحيات إضافية على الجداول نفسها، ويمكننا الاستمرار في استخدام الدور postgis_reader.
-- Add insert/update/delete abilities to our web application
GRANT INSERT,UPDATE,DELETE ON nyc_streets TO app1;
وهذا النوع من الصلاحيات مطلوب مثلًا لخدمة WFS للقراءة والكتابة.
أما المطورون والمحللون فيحتاجون إلى صلاحيات أوسع قليلًا على جداول البيانات الوصفية الرئيسية في PostGIS. سنحتاج إلى دور postgis_writer يمكنه تحرير جداول البيانات الوصفية في PostGIS!
-- Make a postgis writer role
CREATE ROLE postgis_writer;
-- Start by giving it the postgis_reader powers
GRANT postgis_reader TO postgis_writer;
-- Add insert/update/delete powers for the PostGIS tables
GRANT INSERT,UPDATE,DELETE ON spatial_ref_sys TO postgis_writer;
-- Make app1 a PostGIS writer to see if it works!
GRANT postgis_writer TO app1;
جرّب الآن تعليمة SQL لإنشاء الجدول أعلاه بصفتك المستخدم app1 وانظر كيف تسير الأمور!
36.2. التشفير¶
يوفر PostgreSQL الكثير من مرافق التشفير، كثير منها اختياري وبعضها مفعّل افتراضيًا.
افتراضيًا، تُشفَّر جميع كلمات المرور بـ MD5. ويُشفِّر تبادل المصافحة بين العميل والخادم كلمة مرور MD5 تشفيرًا مزدوجًا لمنع إعادة استخدام قيمة التجزئة من قِبل أي شخص يعترض كلمة المرور.
تتوفر اتصالات SSL اختياريًا بين العميل والخادم لتشفير جميع البيانات ومعلومات تسجيل الدخول. كما يتوفر التحقق من الهوية بشهادات SSL عند استخدام اتصالات SSL.
يمكن تشفير الأعمدة داخل قاعدة البيانات باستخدام الوحدة pgcrypto، التي تتضمن خوارزميات التجزئة، والشيفرات المباشرة (blowfish، aes)، وتشفير PGP بالمفتاح العام والمتماثل كليهما.
36.2.1. اتصالات SSL¶
لاستخدام اتصالات SSL، يجب أن يدعم كلٌّ من العميل والخادم بروتوكول SSL.
أولًا، أوقف تشغيل PostgreSQL، لأن تفعيل SSL سيتطلب إعادة التشغيل.
بعد ذلك، نحصل على شهادة SSL ومفتاح أو نولّدهما. يجب ألا تحتوي الشهادة على عبارة مرور، وإلا فلن يتمكن خادم قاعدة البيانات من بدء التشغيل. يمكنك توليد مفتاح موقَّع ذاتيًا كما يلي:
# Create a new certificate, filling out the certification info as prompted openssl req -new -text -out server.req # Strip the passphrase from the certificate openssl rsa -in privkey.pem -out server.key # Convert the certificate into a self-signed cert openssl req -x509 -in server.req -text -key server.key -out server.crt # Set the permission of the key to private read/write chmod og-rwx server.key
انسخ
server.crtوserver.keyإلى مجلد بيانات PostgreSQL.فعّل دعم SSL في الملف
postgresql.confبضبط المعامل "ssl" على "on".أعد الآن تشغيل PostgreSQL؛ أصبح الخادم جاهزًا للعمل بـ SSL.
بعد تفعيل SSL على الخادم، يصبح إنشاء اتصال مشفّر أمرًا سهلًا. في PgAdmin، أنشئ اتصال خادم جديدًا (File > Add Server...)، واضبط المعامل SSL على “require”.
بمجرد الاتصال عبر الاتصال الجديد، يمكنك أن ترى في خصائصه أنه يستخدم اتصال SSL.
بما أن وضع اتصال SSL الافتراضي هو "prefer"، فلا تحتاج حتى إلى تحديد تفضيل SSL عند الاتصال. فالاتصال من طرفية سطر الأوامر psql سيلتقط خيار SSL ويستخدمه افتراضيًا:
psql (8.4.9)
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)
Type "help" for help.
postgres=#
لاحظ كيف تُظهر الطرفية حالة SSL للاتصال.
36.2.2. تشفير البيانات¶
تتضمن الوحدة pgcrypto مجموعة ضخمة من خيارات التشفير، لذا سنعرض فقط أبسط حالة استخدام: تشفير عمود من البيانات باستخدام شيفرة متماثلة.
أولًا، فعّل pgcrypto بتحميل ملف SQL الخاص بها من contrib، إما في PgAdmin أو psql.
pgsql/8.4/share/postgresql/contrib/pgcrypto.sql
ثم اختبر دالة التشفير.
-- encrypt a string using blowfish (bf) SELECT encrypt('this is a test phrase', 'mykey', 'bf');
وتأكد من أنها قابلة للعكس أيضًا!
-- round-trip a string using blowfish (bf) SELECT decrypt(encrypt('this is a test phrase', 'mykey', 'bf'), 'mykey', 'bf');
36.3. التحقق من الهوية¶
يدعم PostgreSQL العديد من طرق التحقق من الهوية المختلفة، لتسهيل التكامل مع معماريات المؤسسات القائمة. ولأغراض الإنتاج، تُستخدم الطرق التالية عادةً:
كلمة المرور (Password) هي النظام الأساسي، حيث تخزّن قاعدة البيانات كلمات المرور مشفّرة بـ MD5.
Kerberos طريقة قياسية للتحقق من الهوية في المؤسسات، وتستخدمها كلتا الآليتين GSSAPI و SSPI في PostgreSQL. وباستخدام SSPI يمكن لـ PostgreSQL التحقق من الهوية مقابل خوادم Windows.
LDAP طريقة شائعة أخرى للتحقق من الهوية في المؤسسات. ويوفر خادم OpenLDAP المضمّن في معظم توزيعات Linux تطبيقًا مفتوح المصدر لـ LDAP.
التحقق من الهوية بـ الشهادات (Certificate) خيار متاح إذا كنت تتوقع أن تتم جميع اتصالات العملاء عبر SSL وكنت قادرًا على إدارة توزيع المفاتيح.
التحقق من الهوية بـ PAM خيار متاح إذا كنت تعمل على Linux أو Solaris وتستخدم آلية PAM لتوفير تحقق شفاف من الهوية.
يتحكم الملف pg_hba.conf في طرق التحقق من الهوية. ويرمز "HBA" في اسم الملف إلى "host based access" (الوصول المعتمد على المضيف)، لأنه إضافة إلى تمكينك من تحديد طريقة التحقق من الهوية لكل قاعدة بيانات، يتيح لك تقييد وصول المضيفين باستخدام عناوين الشبكة.
إليك مثالًا على ملف pg_hba.conf:
# TYPE DATABASE USER CIDR-ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all trust
# IPv4 local connections:
host all all 127.0.0.1/32 trust
# IPv6 local connections:
host all all ::1/128 trust
# remote connections for nyc database only
host nyc all 192.168.1.0/2 ldap
يتكون الملف من خمسة أعمدة
TYPE يحدد نوع الوصول: إما "local" للاتصالات من الخادم نفسه أو "host" للاتصالات البعيدة.
DATABASE يحدد قاعدة البيانات التي يشير إليها سطر الإعداد، أو "all" لجميع قواعد البيانات
USER يحدد المستخدمين الذين يشير إليهم السطر، أو "all" لجميع المستخدمين
CIDR-ADDRESS يحدد قيود الشبكة للاتصالات البعيدة، باستخدام صيغة network/netmask
METHOD يحدد بروتوكول التحقق من الهوية المستخدم. والقيمة "trust" تتخطى التحقق من الهوية تمامًا وتقبل ببساطة أي اسم مستخدم صالح دون تحقق.
من الشائع أن تكون الاتصالات المحلية موثوقة، لأن الوصول إلى الخادم نفسه يكون عادةً مقيّدًا بصلاحيات. والاتصالات البعيدة معطّلة افتراضيًا عند تثبيت PostgreSQL: فإذا أردت الاتصال من أجهزة بعيدة فعليك إضافة مُدخل.
السطر الخاص بـ nyc في المثال أعلاه مثال على مُدخل للوصول البعيد. فمثال nyc يسمح بالوصول المُتحقَّق منه عبر LDAP فقط للأجهزة على الشبكة المحلية (في هذه الحالة الشبكة 192.168.1.) وفقط إلى قاعدة البيانات nyc. وبحسب مستوى أمان شبكتك، ستستخدم صيغًا أكثر أو أقل صرامة من هذه القواعد في بيئة الإنتاج لديك.