نظرة عملية على أفكار دانيال ج. برنشتاين حول الأمن بالتصميم — من qmail إلى Curve25519 — وما يعنيه "تشفير بسيط وقابل للتحقق" في التطبيق.

الأمن بالتصميم يعني بناء نظام بحيث يكون من الصعب ارتكاب الأخطاء الشائعة — ومحدودًا حجم الضرر إذا حدثت أخطاء لا مفر منها. بدلًا من الاعتماد على قائمة طويلة من التذكيرات ("تذكّر التحقق من X، نظّف Y، ضبط Z…")، تصمّم البرمجية بحيث يكون المسار الأكثر أمانًا هو أيضًا الأسهل تنفيذًا.
فكّر فيه مثل تغليف مقاوم للأطفال: لا يفترض أن الجميع سيكونوا حذرين تمامًا؛ يفترض أن البشر متعبون، مشغولون، وأحيانًا مخطئون. التصميم الجيد يقلل مقدار "السلوك المثالي" المطلوب من المطورين والمشغلين والمستخدمين.
مشكلات الأمان غالبًا ما تختبئ في التعقيد: ميزات كثيرة، خيارات كثيرة، تداخلات عديدة بين المكونات. كل مقبض إضافي يمكن أن يخلق وضع فشل جديد — طريقة غير متوقعة ينكسر أو يُساء استخدام النظام بها.
البساطة تساعد عمليًا بطريقتين:
الأمر ليس عن التقشف لذاته. إنه عن الحفاظ على مجموعة السلوكيات صغيرة بما يكفي لتفهمها وتختبرها وتفكّر بشأن ما يحدث عند وقوع خطأ.
يستخدم هذا المقال عمل دانيال ج. برنشتاين كمجموعة أمثلة ملموسة عن الأمن بالتصميم: كيف سعى qmail لتقليل أوضاع الفشل، كيف يمنع التفكير بزمن ثابت التسريبات غير المرئية، وكيف يدفع Curve25519/X25519 وNaCl نحو تشفير يصعب إساءة استخدامه.
ما لن يفعله: لن يقدّم تاريخًا كاملاً للتشفير، ولن يثبت الخوارزميات آمنة، ولن يدّعي وجود مكتبة واحدة "أفضل" لكل منتج. ولن يدّعي أن البنى الجيدة تحل كل شيء — الأنظمة الحقيقية لا تزال تفشل بسبب إدارة المفاتيح، أخطاء التكامل، وفجوات تشغيلية.
الهدف بسيط: إظهار أنماط تصميم تجعل النتائج الآمنة أكثر احتمالًا، حتى لو لم تكن متخصصًا في التشفير.
دانيال ج. برنشتاين (غالبًا "DJB") هو رياضياتي وعالم حاسوب يظهر عمله مرارًا في هندسة الأمن العملية: أنظمة البريد الإلكتروني (qmail)، بُنى وبروتوكولات التشفير (لا سيما Curve25519/X25519)، ومكتبات تُغلف التشفير للاستخدام الواقعي (NaCl).
يستشهد الناس بـ DJB ليس لأنه كتب الطريقة الوحيدة "الصحيحة" للأمن، بل لأن مشاريعه تتشارك في مجموعة ثابتة من الغرائز الهندسية التي تقلّل عدد الطرق التي يمكن أن تسوء بها الأمور.
ثيمة متكررة هي واجهات أصغر وأضيق. إذا كشف النظام عن نقاط دخول أقل وخيارات تهيئة أقل، يصبح مراجعته أسهل، اختباره أسهل، ومن الصعب إساءة استخدامه بالخطأ.
ثيمة أخرى هي الافتراضات الصريحة. كثير من إخفاقات الأمان تنشأ من توقعات غير معلنة — عن العشوائية، سلوك التوقيت، معالجة الأخطاء، أو كيفية تخزين المفاتيح. كتابات وتنفيذات DJB تميل إلى جعل نموذج التهديد ملموسًا: ما الذي نحميه، من من، وبأي شروط.
أخيرًا، هناك ميل نحو الافتراضات الآمنة والصحة المملة. العديد من التصاميم في هذا التقليد تحاول إزالة الحواف الحادة التي تؤدي إلى أخطاء دقيقة: معلمات غامضة، أوضاع اختيارية، وتجاورات أداء قد تتسرب معلومات.
هذا المقال ليس قصة حياة أو نقاشًا حول الشخصيات. إنه قراءة هندسية: ما الأنماط التي يمكنك ملاحظتها في qmail، التفكير بزمن ثابت، Curve25519/X25519، وNaCl، وكيف تتطابق هذه الأنماط مع بناء أنظمة أبسط للتحقق وأقل هشاشة في الإنتاج.
qmail بُني لحل مشكلة غير جذابة جدًا: توصيل البريد reliably مع اعتبار خادم البريد هدفًا عالي القيمة. أنظمة البريد متصلة بالإنترنت، تتلقى مُدخلات عدائية طوال اليوم، وتتعامل مع بيانات حساسة (رسائل، بيانات اعتماد، قواعد توجيه). تاريخيًا، خطأ واحد في خادم بريد أحادي النواة قد يعني اختراقًا كاملًا للنظام — أو فقدان رسائل بصمت لا يلاحظه أحد إلا بعد فوات الأوان.
فكرة محورية في qmail هي تقسيم "توصيل البريد" إلى برامج صغيرة تقوم بمهمة واحدة لكل منها: الاستلام، الطابور، التسليم المحلي، التسليم البعيد، إلخ. لكل جزء واجهة ضيقة ومسؤوليات محدودة.
هذا الفصل مهم لأن الفشل يصبح محليًا:
هذا هو الأمن بالتصميم بشكل عملي: صمّم النظام حتى تصبح "غلطية واحدة" أقل احتمالًا أن تتحول إلى "فشل كلي".
qmail يطبق أيضًا عادات يمكن نقلها خارج البريد الإلكتروني:
الخلاصة ليست "استخدم qmail". الخلاصة أنه غالبًا ما يمكنك الحصول على مكاسب أمنية كبيرة عبر إعادة التصميم حول تقليل أوضاع الفشل — قبل كتابة مزيد من الكود أو إضافة المزيد من المقابض.
"سطح الهجوم" هو مجموع كل الأماكن التي يمكن قرصنة أو خداع النظام عبرها. تشبيه مفيد هو المنزل: كل باب، نافذة، فتحة تسليم، مفتاح احتياطي هو نقطة دخول محتملة. يمكنك تركيب أقفال أفضل، لكنك تصبح أكثر أمانًا أيضًا بوجود نقاط دخول أقل.
البرمجيات مثل ذلك. كل منفذ تفتحه، كل صيغة ملف تقبلها، كل نقطة إدارة تعرضها، كل مقبض تهيئة تضيفه، وكل خطاف ملحقات تدعمه يزيد عدد الطرق التي يمكن أن تخفق فيها الأمور.
"الواجهة الضيقة" هي API تقوم بأقل، تقبل تباينًا أقل، وترفض المدخلات الغامضة. قد يبدو هذا مقيدًا — لكنه أسهل لتأمينه لأن هناك عددًا أقل من مسارات الكود لمراجعتها وتداخلات مفاجئة أقل.
فكر في تصميمين:
التصميم الثاني يقلّل ما يمكن للمهاجم التلاعب به. كما يقلّل ما يمكن لفريقك تهيئته عن طريق الخطأ.
الخيارات تضاعف الاختبارات. إذا دعمت 10 مفاتيح تبديل، فليس لديك 10 سلوكيات — لديك تراكيب. كثير من أخطاء الأمان تعيش في تلك التداخلات: "هذا العلم يعطّل فحصًا"، "هذا الوضع يتخطى التحقق"، "هذا الإعداد القديم يتجاوز حدود المعدل". الواجهات الضيقة تحوّل "أمن حسب اختيارك" إلى مسار واحد مُضاء جيدًا.
استخدم هذه القائمة لرصد سطح الهجوم الذي ينمو بصمت:
عندما لا يمكنك تقليص الواجهة، اجعلها صارمة: تحقق مبكرًا، ارفض الحقول غير المعروفة، واحتفظ بـ"الميزات القوية" خلف نقاط نهاية منفصلة وواضحة النطاق.
سلوك "زمن ثابت" يعني أن عملية الحساب تستغرق (تقريبًا) نفس الوقت بغض النظر عن القيم السرية مثل المفاتيح الخاصة أو nonces أو البتات الوسيطة. الهدف ليس السرعة؛ بل أن تكون مملة: إذا لم يستطع المهاجم ربط زمن التشغيل بالأسرار، يصبح من الصعب عليه استخراج هذه الأسرار بالملاحظة.
تسريبات التوقيت مهمة لأن المهاجمين لا يحتاجون دائمًا لكسر الرياضيات. إذا استطاعوا تشغيل نفس العملية عدة مرات (أو مشاهدتها على عتاد مشترك)، فإن اختلافات صغيرة — ميكروثوانٍ، نانوثوانٍ، أو حتى تأثيرات الكاش — قد تكشف أنماطًا تتراكم إلى استرداد مفاتيح.
حتى الكود "الطبيعي" قد يتصرف بشكل مختلف اعتمادًا على البيانات:
if (secret_bit) { ... } يغير تدفّق التحكم وغالبًا الزمن.لا تحتاج لقراءة التجميع للحصول على قيمة من التدقيق:
التفكير بزمن ثابت أقل عن بطولات وأكثر عن انضباط: صمّم الكود بحيث لا تُمكّن الأسرار من توجيه الزمن أساسًا.
تبادل مفاتيح المنحنى الإهليلجي هو طريقة لجعل جهازين يولدان نفس السر المشترك رغم أنهما يرسلان فقط رسائل "عامة" عبر الشبكة. كل طرف يولد قيمة خاصة (تُبقى سرًا) وقيمة عامة مقابلة (آمنة للإرسال). بعد تبادل القيم العامة، يجمع الطرفان القيمة الخاصة مع القيمة العامة للطرف الآخر ليحصلا على نفس السر المشترك. المتنصت يرى القيم العامة لكنه لا يستطيع عمليًا إعادة بناء السر المشترك، فيستطيع الطرفان اشتقاق مفاتيح تشفير والحديث بخصوصية.
Curve25519 هو المنحنى الأساس؛ X25519 هو دالة تبادل المفاتيح المعيارية "افعل هذا بالتحديد" المبنية عليه. جاذبيتهما في الغالب هي الأمن بالتصميم: أخطاء أقل للمستخدم، اختيارات معلمات أقل، وطرق أقل لاختيار ضبط غير آمن.
كما أنهما سريعان عبر مجموعة واسعة من الأجهزة، وهو أمر مهم للخوادم التي تتعامل مع اتصالات عديدة وللهواتف التي تحاول حفظ البطارية. ويشجّع التصميم على تنفيذات يمكن أن تحافظ على زمن ثابت بسهولة أكبر (مقاومة لهجمات التوقيت)، ما يقلّل خطر استخراج الأسرار عبر اختلافات الأداء الدقيقة.
X25519 يعطيك اتفاقية مفاتيح: يساعد طرفين على اشتقاق سر مشترك للتشفير المتماثل.
إنه لا يوفّر مصادقة بنفسه. إذا شغّلت X25519 بدون التحقق أيضًا من هوية الطرف الذي تتحدث إليه (مثل الشهادات، التوقيعات، أو مفتاح مشترك مسبقًا)، يمكنك أن تُخدع بالتواصل بشكل آمن مع الطرف الخطأ. بمعنى آخر: X25519 يمنع التنصت لكنه لا يمنع الانتحال بمفرده.
NaCl (مكتبة الشبكات والتشفير) بُنيت بهدف بسيط: صعّب على مطوّري التطبيقات تركيب تشفير غير آمن بالخطأ. بدلًا من تقديم بوفيه من الخوارزميات والوضعيات وقواعد الحشو ومقابض التهيئة، تدفعك NaCl نحو مجموعة صغيرة من العمليات عالية المستوى الموصولة بالفعل بطرق آمنة.
box وsecretbox كلبِنات بناء أكثر أمانًاواجهات NaCl مسمّاة بما تريد فعله، لا بما تريد استخدامه من البِنى.
crypto_box ("box"): تشفير بالمفتاح العام مع مصادقة. تعطيه مفتاحك الخاص، المفتاح العام للمستلم، nonce، ورسالة. تحصل على نص مشفّر يخفي الرسالة ويثبت أنها جاءت من من يعرف المفتاح الصحيح.crypto_secretbox ("secretbox"): تشفير بمفتاح مشترك مع مصادقة. نفس الفكرة، لكن بمفتاح مشترك واحد.الفائدة الأساسية أنك لا تختار منفصلًا "وضع التشفير" و"خوارزمية MAC" ثم تأمل أنك جمعتهم بشكل صحيح. افتراضات NaCl تُجبر تركيبات مقاومة إساءة الاستخدام (encrypt-then-authenticate)، لذلك احتمالات فشل شائعة—كنسيان فحوص السلامة—أقل بكثير.
صرامة NaCl قد تشعر بأنها مقيدة إذا كنت تحتاج توافقًا مع بروتوكولات قديمة، صيغ متخصصة، أو خوارزميات مفروضة تنظيميًا. أنت تتبادل "أستطيع ضبط كل معلمة" بـ "أستطيع شحن شيء آمن دون أن أكون خبير تشفير".
بالنسبة لكثير من المنتجات، هذه هي النقطة بالضبط: قيد مساحة التصميم بحيث توجد أخطاء أقل. إذا كنت حقًا بحاجة لتخصيص، يمكنك النزول إلى مبتدئات أدنى — لكنك تعود طواعية إلى الحواف الحادة.
"آمن افتراضيًا" يعني أن الخيار الأخطر والأكثر عقلانية هو ما تحصل عليه عندما لا تفعل شيئًا. إذا قام المطور بتثبيت مكتبة، نسخ مثال سريع، أو استخدم إعدادات الإطار الافتراضية، يجب أن تكون النتيجة صعبة الإساءة وصعبة إضعافها عن غير قصد.
الإعدادات الافتراضية مهمة لأن أغلب الأنظمة الواقعية تعمل بها. الفرق تتسارع، الوثائق تُقرأ بسرعة، والتهيئة تتوسع عضويًا. إذا كان الافتراضي "مرنًا"، فذلك غالبًا ما يترجم إلى "سهل التهيئة بشكل خاطئ".
إخفاقات التشفير ليست دائمًا ناجمة عن "رياضيات سيئة". كثيرًا ما تكون ناجمة عن اختيار إعداد خطر لأنه متاح، مألوف، أو سهل.
فخاخ افتراضية شائعة:
فضّل الحزم التي تجعل المسار الآمن هو الأسهل: مبتدئات مُراجعة، معلمات محافظة، وواجهات لا تطلب منك اتخاذ قرارات هشة. إذا أجبرت المكتبة على أن تختار بين عشرة خوارزميات وخمسة أوضاع وترميزات متعددة، فأنت تُجري هندسة الأمان عبر التهيئة.
عندما تستطيع، اختر مكتبات وتصاميم تُ:
الأمن بالتصميم جزئيًا هو رفض تحويل كل قرار إلى قائمة منسدلة.
"القابلية للتحقق" لا تعني "مثبت رسميًا" في معظم فرق المنتجات. تعني أنك تستطيع بناء ثقة بسرعة وبشكل متكرر، ومع فرص أقل لسوء الفهم لما يفعله الكود.
تصبح قاعدة الكود أكثر قابلية للتحقق عندما:
كل فرع، وضع، وميزة اختيارية يضاعف ما يجب أن يفكر فيه المراجعون.
المسارات الأبسط تضيق مجموعة الحالات الممكنة، مما يحسن جودة المراجعة بطريقتين:
اجعل الأمور مملة وقابلة للتكرار:
هذا المزيج لن يحل محل المراجعة الخبيرة، لكنه يرفع الحد الأدنى: مفاجآت أقل، كشف أسرع، وكود يمكنك التفكير فيه فعلا.
حتى لو اخترت مبتدئات محترمة مثل X25519 أو API صغير على نمط NaCl "box"/"secretbox"، لا تزال الأنظمة تنهار في الأجزاء الفوضوية: التكامل، الترميز، والتشغيل. معظم الحوادث الواقعية ليست "الرياضيات كانت خاطئة"، بل "استخدمت الرياضيات بشكل خاطئ".
أخطاء التعامل مع المفاتيح شائعة: إعادة استخدام مفاتيح طويلة الأمد حيث يُتوقع مفتاح عابر، تخزين المفاتيح في التحكم بالمصدر، أو الخلط بين "المفتاح العام" و"المفتاح السري" لأنهما مجرد مصفوفات بايت.
سوء استخدام nonce متكرر. تتطلب كثير من مخططات التشفير المُصدق فريدًا لكل مفتاح. إذا تم تكرار nonce (غالبًا عبر إعادة ضبط عداد، سباقات متعددة العمليات، أو افتراضات "عشوائية كافية"), قد تخسر السرية أو السلامة.
مشكلات الترميز والتحليل تخلق أخطاء صامتة: التباس base64 مقابل hex، فقدان أصفار بادئة، اختلافات endianness، أو قبول ترميزات متعددة تقارن بشكل مختلف. هذه الأخطاء يمكن أن تحول "توقيع موثّق" إلى "شيء آخر موثّق".
معالجة الأخطاء قد تكون خطرة في كلا الاتجاهين: إرجاع أخطاء مفصّلة تساعد المهاجمين، أو تجاهل فشل التحقق ومواصلة التنفيذ على أي حال.
الأسرار تتسرب عبر السجلات، تقارير التعطل، التحليلات، ونقاط تصحيح الأخطاء. المفاتيح تنتهي أيضًا في النسخ الاحتياطية، صور الـVM، ومتغيرات البيئة المشتركة على نطاق واسع. في الوقت نفسه، تحديثات التبعيات (أو نقصها) يمكن أن تتركك على تنفيذ عرضة حتى لو كان التصميم سليمًا.
المبتدئات الجيدة لا تنتج منتجًا آمنًا تلقائيًا. كلما زادت الخيارات التي تكشفها—أوضاع، حشوات، ترميزات، "تعديلات" مخصصة—زاد عدد الطرق التي يمكن للفرق أن تبني بها شيئًا هشًا عن طريق الخطأ. يبدأ نهج الأمن بالتصميم باختيار مسار هندسي يقلل نقاط القرار.
استخدم مكتبة عالية المستوى (واجهات عملية واحدة مثل "شفر هذه الرسالة لذلك المستلم") عندما:
جَمّع مبتدئات أدنى مستوى (AEADs، هاشات، تبادل مفاتيح) فقط عندما:
قاعدة مفيدة: إذا كان مستند التصميم لديك يحتوي "سنختار الوضع لاحقًا" أو "سنتوخى الحذر مع nonces"، فأنت بالفعل تدفع ثمن وجود الكثير من المقابض.
اطلب إجابات ملموسة، لا لغة تسويقية:
عامل التشفير ككود حرج للسلامة: حافظ على سطح API صغير، ثبّت الإصدارات، أضف اختبارات الأجوبة المعروفة، وشغّل fuzzing على التحليل/التسلسلات. وثّق ما لن تدعمه (خوارزميات، صيغ قديمة)، وابتكر ترحيلات بدلًا من "مفاتيح التوافق" التي تبقى للأبد.
الأمن بالتصميم ليس أداة تشتريها—إنه مجموعة عادات تجعل فئات كاملة من الأخطاء أصعب الإنشاء. الخيط المشترك عبر هندسة نمط DJB هو: اجعل الأشياء بسيطة بما يكفي للتفكير فيها، صغ الواجهات بكل ما يكفي لمنع سوء الاستخدام، اكتب كودًا يتصرف بنفس الطريقة حتى تحت الهجوم، واختر إعدادات تفشل بأمان.
إذا أردت قائمة تدقيق منظمة لهذه الخطوات، فكر في إضافة صفحة جرد تشفير داخلية إلى وثائق الأمان لديك (مثل /security).
هذه الأفكار ليست محصورة بمكتبات التشفير—تنطبق على طريقة بناء وشحن البرمجيات عمومًا. إذا كنت تستخدم سير عمل توليدي (مثل Koder.ai أو أطر توليد التطبيقات عبر الدردشة)، تظهر نفس المبادئ كقيود على المنتج: دعم عدد صغير من الستاكات المدعومة، التركيز على التخطيط قبل التوليد، وجعل التراجع رخيصًا.
عمليًا، ميزات مثل وضع التخطيط، اللقطات والتراجع، وتصدير الشيفرة المصدرية تساعد في تقليل "نطاق الانفجار" للأخطاء: يمكنك مراجعة النية قبل تطبيق التغييرات، التراجع بسرعة عند حدوث خطأ، والتحقق أن ما يعمل يطابق ما تم إنشاؤه. هذه نفس غريزة الأمن بالتصميم في عزل qmail — مطبّقة على خطوط توصيل النشر الحديثة.
الأمن بالتصميم يعني تصميم البرمجيات بحيث يكون المسار الأكثر أمانًا هو أيضًا الأسهل اتباعًا. بدلًا من الاعتماد على قوائم تحقق طويلة من قبل الأشخاص، تقيد النظام بحيث يصبح من الصعب ارتكاب الأخطاء الشائعة وتُقلَل آثار الأخطاء الحتمية (تقليل "نطاق الانفجار").
التعقيد يخلق تداخلات وحالات حافة يصعب اختبارها وسهلة التخطيط الخاطئ.
تفاصيل عملية لفوائد البساطة:
الواجهة الضيقة تقوم بأقل وتقبل أقل من التباين. تتجنب المدخلات المبهمة وتقلّل الأوضاع الاختيارية التي تخلق “أمن حسب التهيئة”.
نهج عملي:
qmail يجزّئ معالجة البريد إلى برامج صغيرة (استلام، طابور، تسليم محلي، تسليم عن بُعد...) كل منها مسؤول عن مهمة ضيقة. هذا يقلّل أوضاع الفشل لأن:
سلوك بزمن ثابت يهدف إلى جعل زمن التنفيذ (وغالبًا أنماط وصول الذاكرة) مستقلة عن القيم السرية. هذا مهم لأن المهاجمين أحيانًا يستطيعون استنتاج أسرار بقياس الفروق الزمنية أو تأثيرات الكاش أو فرق “المسار السريع/البطيء” عبر تجارب متعددة.
الفكرة ليست مجرد اختيار خوارزميات قوية، بل منع "التسريبات غير المرئية" الناتجة عن الزمن أو الذاكرة.
ابدأ بتحديد ما هو سِرِّي (مفاتيح خاصة، أسرار مشتركة، مفاتيح MAC، علامات التوثيق)، ثم ابحث عن مواضع يؤثر فيها السر على تدفّق التحكم أو وصول الذاكرة.
علامات تحذّر للبحث عنها:
if تعتمد على بيانات سريةوتحقق من أن تبعية التشفير التي تستخدمها تذكر صراحة أي عمليات يُفترض أن تكون بزمن ثابت.
X25519 هو دالة تبادل مفاتيح معيارية مبنية على Curve25519. تصبح مشهورة لأنها تقلّل أخطاء المستخدم: عدد أقل من المعاملات للاختيار، أداء جيد عبر العتاد، وتصميم يساعد على تنفيذات يمكن أن تكون بزمن ثابت.
إنها مسار افتراضي أكثر أمانًا لتبادل المفاتيح—طالما أنك تتعامل أيضًا مع المصادقة وإدارة المفاتيح بشكل صحيح.
لا. X25519 يوفر اتفاقية مفاتيح (سرّ مشترك) لكنه لا يثبت هوية الطرف الآخر.
لمنع الانتحال، قم بإقرانه بمصادقة مثل:
بدون مصادقة، قد تتواصل "بشكل مشفر" مع الطرف الخطأ.
فكرة NaCl هي تقليل الأخطاء عبر تقديم عمليات عالية المستوى مُركّبة بأمان بدلًا من تقديم باقة من الخوارزميات والوضعيات.
بناءان شائعان:
crypto_box: تشفير مُصدق بالمفتاح العام (مفتاحك الخاص + مفتاح المستلم + nonce + رسالة → نص مشفّر)crypto_secretbox: تشفير مُصدق بمفتاح مشتركالفائدة العملية: تجنّب أخطاء التركيب الشائعة (مثل التشفير بدون حماية سلامة).
حتى مع مفردات جيدة، تفشل الأنظمة عندما تكون التكاملات والعمليات فوضوية. أخطاء شائعة:
تخفيفات: