لقد حدث أنني أحب حقًا استخدام SQLite DBMS.
عند البرمجة في المجمّع ، أحتاج أحيانًا إلى نظام إدارة قواعد بيانات كامل. نادرا ما تتجاوز برامجي بضع مئات من الكيلوبايت. من الواضح أن استخدام نظام إدارة قواعد البيانات (DBMS) الذي يبلغ عدة مئات من الميغابايتات أمر مثير للسخرية على الأقل ، ولكنه في النهاية غير مريح للغاية - تزداد متطلبات الأجهزة وتعقيد التثبيت والتكوين فورًا ، ونتيجة لذلك ، تتناقص موثوقية النظام بأكمله.
سكليتي هي مسألة مختلفة تماما. أولاً ، إنها صغيرة - فقط بضع مئات من الكيلوبايت ، وهي إضافة رائعة إلى برامج المجمعات المدمجة. ثانياً ، إنه نظام تخزين بيانات موثوق للغاية. إنها لا تحتاج إلى أي إعدادات وإعدادات خاصة. حسنا ، بالنسبة للأداء - وليس الأخير.
على سبيل المثال ، استخدمت SQLite في محرك المنتدى AsmBB الذي كتبت عنه بالفعل على Habré. (بالمناسبة ، بعد ذلك لم يسقط ).
منذ ذلك الوقت ، تم تطوير المشروع ببطء ولكن بثبات. ظهرت ميزات جديدة ، وزيادة الأمن والأداء.
ثم في أحد الأيام فكرت في كيفية زيادة الأمن الجيد بالفعل للمشروع. واعتقدت على الفور أنه سيكون من الجيد تشفير قاعدة بيانات المنتدى. في الواقع ، حتى لو تسربت قاعدة البيانات ، فلن يتمكن أي شخص من الوصول إلى البيانات الشخصية للمستخدمين.
أظهر البحث السريع على الإنترنت أن هناك العديد من ملحقات SQLite لتشفير قاعدة البيانات. لسوء الحظ ، ملحق SEE الرسمي ليس مجانيًا ويُباع عمومًا مقابل المال.
لكن ، بالطبع ، المكان المقدس ليس فارغًا على الإطلاق ، وقد تعثرت على الفور في امتداد SQLeet . وفي ذلك أحببت حرفيا كل شيء.
يستخدم SQLeet خوارزمية ChaCha20 لتشفير قاعدة البيانات. يتم حساب مفتاح التشفير من خلال PBKDF2-HMAC-SHA256 باستخدام ملح 16 بايت وتكرار 12345 تجزئة. للمصادقة ، يتم استخدام Poly1305.
يتم توزيع كل من SQLeet و SQLite تحت المجال العام (المجال العام). هذا مناسب لأنه لا يزيد من فوضى الترخيص في المشروع.
لا يزال SQLeet مضغوط للغاية. كل الكود لا يستغرق سوى حوالي واحد ونصف ألف سطر في C وليس له تبعيات خارجية.
يتم دعم المشروع بنشاط ويقوم المؤلف بالرد السريع على الأسئلة وإصلاح الأخطاء ، إن وجدت.
يتم توزيع SQLeet بنفس طريقة SQLite - في شكل ملف مصدر C واحد يمكن تجميعه ببساطة بنفس طريقة تجميع SQLite.
علاوة على ذلك ، نظرًا لأن الامتداد لا يغير رمز SQLite بأي طريقة ، يمكن تحديث قاعدة البيانات الرئيسية لنظام إدارة قواعد البيانات بكل بساطة - عن طريق استبدال ملف sqlite3.c
وإعادة إنشاء المصدر المدمج.
نظرًا لأنني لا أستخدم التحويل البرمجي القياسي تمامًا في AsmBB (يتم تجميع SQLite في AsmBB عبر MUSL libc ) ، وأنا لست مبرمجًا C ، بالنسبة لي تعتبر بساطة التجميع مهمة جدًا.
على سبيل المثال ، إليك رمز bash الذي أستخدمه لتنزيل أحدث إصدار من SQLeet وإنشاء المصدر وإنشاءه:
wget -q -O - https://github.com/resilar/sqleet/archive/master.tar.gz | tar -xz cd ./sqleet-master script/amalgamate.sh < ./sqleet.c > ../sqlite3.c cd .. rm -rf ./sqleet-master/
والنتيجة هي ملف sqlite3.c
الذي يمكن إدراجه حيث تم إدراج ملف SQLite الأصلي من قبل واستخدامه بنفس الطريقة.
استخدام الامتداد لا يختلف أيضًا عن استخدام SQLite. الفرق الوحيد هو أنه إذا كانت قاعدة البيانات مشفرة ، فبعد الفتح مباشرة ، من الضروري استدعاء الدالة sqlite3_key () ، التي تحدد كلمة مرور التشفير فيها. حسنًا ، أو حتى أفضل ، فقط قم بتنفيذ SQL pragma key='%%'
. (هذا أفضل لأن واجهة برمجة تطبيقات SQLite لا تتغير و
يمكنك دائمًا استبدال SQLeet بـ SQLite والعكس صحيح).
يحدث تشفير قاعدة البيانات الأولية ، وكذلك استبدال كلمة المرور ، من خلال دالة pragma rekey='%NEW_PASSWORD%'
sqlite3_rekey()
أو pragma باستخدام الأمر pragma rekey='%NEW_PASSWORD%'
.
وهنا كان لدي مثل هذا السؤال. من أين تأتي كلمة المرور؟ بعد كل شيء ، إذا تم تخزين كلمة المرور على الخادم في بعض الملفات ، فسيتمكن المتسلل المحتمل من قراءتها.
لذلك قررت أن أفعل ذلك بطريقة مختلفة. الحقيقة هي أن AsmBB هو تطبيق FastCGI طويل العمر. بمجرد إطلاقه على الخادم ، فإنه يعمل لعدة أشهر وحتى سنوات دون الحاجة إلى إعادة تشغيل الكمبيوتر.
وإذا كان الأمر كذلك ، فيمكن للمسؤول ببساطة إدخال كلمة المرور من خلال واجهة الويب فور بدء تشغيل AsmBB. وبالتالي ، توجد كلمة المرور فقط في ذاكرة الوصول العشوائي وفقط أثناء تنفيذ طلب POST أثناء تشغيل التطبيق. (بالطبع ، لا تنس أن تستبعد كل الذاكرة التي توجد بها كلمة المرور أثناء تنفيذ طلب POST.)
من كلمة المرور المحددة ، يقوم SQLeet بإنشاء مفتاح تشفير عبر PBKDF2-HMAC-SHA256 ، ويتم تخزين هذا المفتاح أيضًا في ذاكرة الوصول العشوائي فقط.
بالطبع ، هذا القرار غير كامل. ربما يمكن العثور على مفتاح التشفير في ذاكرة RAM ، أثناء تنفيذ AsmBB ، إذا كان لدى المهاجم حقوق المسؤول.
لكن رغم ذلك ، لا يزال النظام أكثر أمانًا من عدم التشفير. على سبيل المثال ، يمكن الآن تخزين النسخ الاحتياطية لقاعدة البيانات في كل مكان وإرسالها عبر قنوات مفتوحة دون خوف من تسرب البيانات.
بالمناسبة ، هناك أشعل النار التي يمكنك خطوة على استخدام SQLeet (أو ملحقات تشفير SQLite أخرى). وأنا بالطبع صعدت عليهم.
المشكلة هي حجم صفحة قاعدة البيانات. في إصدارات SQLite أقدم من 3.12.0 (مارس 2016) ، كان حجم الصفحة الافتراضي 1024 بايت. في v3.12.0 ، صنع 4096 بايت. هذا الحجم ، يمكن لمستخدم قاعدة البيانات تغيير لأسباب الأداء ، وحجم الصفحة مكتوب في قاعدة البيانات نفسها.
ولكن إذا كانت قاعدة البيانات مشفرة ، فلا يمكن قراءة حجم الصفحة ، ولغرض فك التشفير ، يلزم هذا الحجم ، لأن كل كتلة يتم تشفيرها بشكل منفصل.
لذلك ، إذا قمت بتشفير قاعدة بيانات بحجم صفحة غير قياسي (بالنسبة لـ SQLeet ، يكون المعيار 4096 بايت) ، فلن تكون قادرًا على فك تشفيرها ، حتى إذا قمت بتعيين كلمة المرور الصحيحة.
تم إصلاح هذا ببساطة - قبل تعيين كلمة المرور عبر sqlite3_key()
أو pragma key='%%'
، تحتاج إلى تعيين حجم الصفحة الصحيح عبر pragma page_size=%%
.
هناك مشكلة أخرى محتملة وهي أنه بعد التشفير ، لن يتمكن نظام التشغيل بعد الآن من إدراك أن الملف عبارة عن قاعدة بيانات SQLite. هذا (بقدر ما أقرأ) يؤدي في بعض الأحيان إلى بعض المشاكل ، لا سيما في دائرة الرقابة الداخلية. هناك حل لهذه المشكلة ، فقط لا تشفير أول 32 بايت من الملف ، لكنني لم أخوض في التفاصيل.
وأخيرا ، عن الأداء. SQLeet سريع جدا. بعد التشفير ، لم ألاحظ أي تباطؤ في النظام على خلفية التقلبات العادية في أداء VPS. قد تظهر قياسات الدقة نوعًا من التباطؤ ، ولكن من المحتمل أن يكون ذلك في أقل من 10٪ من سرعة قاعدة البيانات غير المشفرة.
بالطبع ، هناك ملحقات SQLite مجانية أخرى للتشفير. على سبيل المثال ، SQLcipher . لم يناسبني لأنه يحتوي على ترخيص توزيع مختلف (BSD) ، الرمز أكبر بكثير وهناك تبعيات خارجية.
ولكن ، من ناحية أخرى ، يعد SQLcipher أقدم بكثير وبالتالي (ربما) أكثر استقرارًا. شخص ما يمكن أن تأتي في متناول اليدين.