ستان درابكين. مصائد التشفير عالية المستوى في .NET

ستان درابكين هو خبير في الأمن والامتثال ولديه أكثر من 16 عامًا من الخبرة مع .NET Framework (بدءًا من .NET 1.0-beta في عام 2001). لسوء الحظ ، هو نفسه لا يكتب مقالات باللغة الروسية ، لذلك اتفقنا معه على نشر ترجمة لتقريره مع DotNext Piter . فاز هذا التقرير بالمركز الأول في المؤتمر!

التشفير المتماثل ، غير المتماثل ، الهجين ، المستوى العالي ، المستوى المنخفض ، الدفق والتشفير البيضاوي الحديث. ستة وخمسون دقيقة من الفيديو حول التشفير ، وأسرع بكثير - في شكل نص.



تحت القطع - مقاطع الفيديو والشرائح والترجمة. استمتع بالقراءة!


شرائح

اسمي ستان درابكين ، وأنا المدير الفني لشركة متخصصة في أمن المعلومات والامتثال التنظيمي. بالإضافة إلى ذلك ، أنا مؤلف العديد من المكتبات مفتوحة المصدر ، والتي لاقت قبولًا كبيرًا من المجتمع. كم سمع عن جحيم ؟ توضح هذه المكتبة النهج الصحيح للتشفير في .NET ، وينفذ TinyORM micro-ORM لـ .NET. بالإضافة إلى ذلك ، لقد كتبت العديد من الكتب التي قد تكون ذات صلة بموضوع مقالة اليوم. واحد منهم ، إصدار 2014 ، هو "أمان مدفوعة. NET" ، والآخر لعام 2017 هو "أمان التطبيق في .NET ، بإيجاز".

أولاً ، سنتحدث عن ما أسميه المراحل الأربع للتنوير المشفر. ثم سيتبع موضوعان رئيسيان ، في الأول سنتحدث عن التشفير المتماثل ، في الثاني - عن التماثل والهجين. في الجزء الأول ، نقارن التشفير عالي المستوى ومنخفض المستوى ونلقي نظرة على مثال على تشفير التدفق. في الجزء الثاني ، سيكون لدينا العديد من "المغامرات" مع RSA ، وبعد ذلك سنتعرف على التشفير الإهليلجي الحديث.

إذن كيف تبدو هذه المراحل من التنوير المشفر؟ المرحلة الأولى - "XOR رائع جدًا ، انظر ، أمي ، كيف يمكنني!" من المؤكد أن العديد منكم على دراية بهذه المرحلة ويدركون عجائب وظيفة XOR. ولكن ، آمل أن تكون معظم هذه المرحلة قد نمت وانتقلت إلى المرحلة التالية ، أي تعلمت أداء التشفير وفك التشفير باستخدام AES (معيار التشفير المتقدم) ، خوارزمية معروفة ومحترمة للغاية. معظم المطورين الذين لا يزورون DotNext هم في هذه المرحلة. ولكن نظرًا لأنك تتبع DotNext وأنت على دراية بالتقارير حول مخاطر واجهات برمجة التطبيقات ذات المستوى المنخفض ، فمن المرجح أن تكون في المرحلة التالية - "فعلت كل شيء (أ) بشكل غير صحيح ، أحتاج إلى التبديل إلى واجهات برمجة التطبيقات عالية المستوى". حسنًا ، لإكمال الصورة ، سأذكر أيضًا المرحلة الأخيرة - إدراك أنه مع أفضل حل للمشكلة ، قد لا تكون هناك حاجة إلى التشفير على الإطلاق. هذه المرحلة هي الأصعب في الوصول إليها ، وهناك عدد قليل من الناس عليها. مثال على ذلك هو بيتر جي نيومان ، الذي قال ما يلي: "إذا كنت تعتقد أن حل مشكلتك يكمن في التشفير ، فأنت لا تفهم ماهية مشكلتك بالضبط".

نوقشت حقيقة أن التشفير منخفض المستوى خطير في العديد من التقارير حول .NET. يمكنك الرجوع إلى تقرير فلاديمير كوتشيتكوف في عام 2015 ، "مطبات System.Security.Cryptography" . فكرته الرئيسية هي أنه في كل مرحلة من العمل مع واجهات برمجة تطبيقات التشفير منخفضة المستوى ، دون معرفة ذلك ، نتخذ العديد من القرارات ، والتي لا نملك الكثير منها للمعرفة المناسبة. الاستنتاج الرئيسي هو أنه ، من الناحية المثالية ، يجب استخدام التشفير عالي المستوى بدلاً من التشفير منخفض المستوى. هذا استنتاج رائع ، لكنه يقودنا إلى مشكلة أخرى - هل نعرف بالضبط كيف يجب أن يبدو التشفير عالي المستوى؟ لنتحدث قليلا عن ذلك.

حدد سمات واجهة برمجة تطبيقات التشفير غير عالية المستوى. بادئ ذي بدء ، لن تعطي واجهة برمجة التطبيقات هذه انطباعًا بأنها أصلية في .NET ؛ بدلاً من ذلك ، ستبدو وكأنها غلاف منخفض المستوى. علاوة على ذلك ، سيكون من السهل استخدام واجهة برمجة التطبيقات هذه بشكل غير صحيح ، أي ليس كما ينبغي. بالإضافة إلى ذلك ، سيجبرك على إنشاء العديد من الأشياء الغريبة ذات المستوى المنخفض - غير المتجه ، وناقلات التهيئة ، وما شابه. ستجبرك واجهة برمجة التطبيقات هذه على اتخاذ قرارات غير سارة قد لا تكون مستعدًا لها - اختر الخوارزميات وأوضاع الحشو والأحجام الرئيسية وغير المنفصلة وما إلى ذلك. لن تحتوي أيضًا على واجهة برمجة التطبيقات الصحيحة للبث (واجهة برمجة تطبيقات البث) - سنتحدث عن الشكل الذي يجب أن تبدو عليه هذه الأخيرة.

في المقابل ، كيف يجب أن تبدو API التشفير عالية المستوى؟ أعتقد أنه يجب أن يكون بديهيًا وموجزًا ​​لكل من قارئ الشفرة والكاتب. علاوة على ذلك ، يجب أن تكون واجهة برمجة التطبيقات هذه سهلة التعلم والاستخدام ، ويجب أن يكون من الصعب للغاية تطبيقها بطريقة خاطئة. يجب أن يكون قويًا أيضًا ، أي أنه يجب أن يسمح لنا بتحقيق هدفنا مع القليل من الجهد ، وكمية صغيرة من التعليمات البرمجية. أخيرًا ، يجب ألا تحتوي واجهة برمجة التطبيقات هذه على قائمة طويلة من القيود والتنبيهات والحالات الخاصة بشكل عام - يجب أن يكون هناك حد أدنى من الأشياء التي يجب تذكرها عند العمل معها ، وبعبارة أخرى - يجب أن تتميز بمستوى منخفض من التداخل (الاحتكاك المنخفض) ، يجب مجرد عمل دون أي تحفظات.

بعد التعامل مع متطلبات API التشفير عالي المستوى لـ .NET ، كيف يمكننا العثور عليه الآن؟ يمكنك تجربة google فقط ، ولكن ذلك سيكون بدائيًا للغاية - نحن مطورون محترفون ، وهذه ليست طريقتنا. لذلك ، نحن نحقق في هذه المشكلة ونختبر بدائل مختلفة. ولكن من أجل هذا ، نحتاج أولاً إلى أن نعوض لأنفسنا الفكرة الصحيحة لما هو التشفير المصدق ، ولهذا نحتاج إلى فهم المفاهيم الأساسية. وهي كما يلي: نص عادي P (نص عادي) ، والذي نقوم بتحويله إلى نص مشفر C (نص مشفر) بنفس الطول باستخدام بعض المفتاح السري K (مفتاح). كما ترون ، نحن نعمل حتى الآن مع مخطط بسيط للغاية. بالإضافة إلى ذلك ، لدينا أيضًا علامة مصادقة T و nonce N. معلمة مهمة هي N̅ ، أي إعادة استخدام nonce بمفتاح واحد. كما يعلم الكثير منكم على الأرجح ، فإنه يؤدي إلى انتهاك سرية النص ، وهو أمر غير مرغوب فيه بشكل واضح. مفهوم آخر مهم هو AD (البيانات المرتبطة) ، أي البيانات المرتبطة. هذه بيانات اختيارية مصادق عليها ولكنها لا تشارك في التشفير وفك التشفير.



بعد فهم المفاهيم الأساسية ، دعنا نلقي نظرة على الخيارات المختلفة لمكتبات التشفير لـ .NET. لنبدأ بتحليل Libsodium.NET. كم منكم يعرفها؟ كما أرى ، البعض مألوف.

nonce = SecretAeadAes.GenerateNonce(); c = SecretAeadAes.Encrypt(p, nonce, key, ad); d = SecretAeadAes.Decrypt(c, nonce, key, ad); 

إليك كود C # الذي يتم من خلاله التشفير باستخدام Libsodium.NET . للوهلة الأولى ، إنه بسيط وموجز للغاية: في السطر الأول ، يتم إنشاء nonce ، والذي يتم استخدامه بعد ذلك في السطر الثاني ، حيث يتم التشفير نفسه ، وفي الثالث ، حيث يتم فك تشفير النص. يبدو - ما هي الصعوبات التي يمكن أن تكون هناك؟ بادئ ذي بدء ، يقدم Libsodium.NET ليس واحدًا ، ولكن ثلاث طرق تشفير متناظرة مختلفة:

تايمز

 nonce = SecretAeadAes.GenerateNonce(); c = SecretAeadAes.Encrypt(p, nonce, key, ad); d = SecretAeadAes.Decrypt(c, nonce, key, ad); 

اثنان

 nonce = SecretAead.GenerateNonce(); c = SecretAead.Encrypt(p, nonce, key, ad); d = SecretAead.Decrypt(c, nonce, key. ad); 

ثلاثة

 nonce = SecretBox.GenerateNonce(); c = SecretBox.Create(p, nonce, key); d = SecretBox.Open(c, nonce, key); 

من الواضح أن السؤال الذي يطرح نفسه - أيهما أفضل في وضعك المحدد؟ للإجابة عليه ، تحتاج إلى الدخول في هذه الأساليب ، والتي سنفعلها الآن.

الطريقة الأولى ، SecretAeadAes ، تستخدم AES-GCM مع SecretAeadAes 96-bit. من المهم أن يكون لديه قائمة طويلة من القيود. على سبيل المثال ، عند استخدامه ، يجب ألا تقوم بتشفير أكثر من 550 جيجا بايت بمفتاح واحد ، ويجب ألا يكون هناك أكثر من 64 جيجا بايت في رسالة واحدة بحد أقصى 2 32 رسالة. علاوة على ذلك ، لا تحذر المكتبة من الاقتراب من هذه القيود ، تحتاج إلى تتبعها بنفسك ، مما يخلق عبئًا إضافيًا عليك كمطور.

الطريقة الثانية ، SecretAead تستخدم مجموعة تشفير مختلفة ، ChaCha20/Poly1305 مع ChaCha20/Poly1305 64 بت أصغر بكثير. مثل هذه السمة الصغيرة تجعل الاصطدامات محتملة للغاية ، ولهذا السبب وحده ، يجب ألا تستخدم هذه الطريقة - إلا في حالات نادرة جدًا وشريطة أن تكون على دراية جيدة بالموضوع.

وأخيرًا ، الطريقة الثالثة ، SecretBox . تجدر الإشارة على الفور إلى عدم وجود بيانات مرتبطة في وسيطات واجهة برمجة التطبيقات هذه. إذا كنت بحاجة إلى تشفير مصدق مع م ، فهذه الطريقة ليست مناسبة لك. تسمى خوارزمية التشفير المستخدمة هنا xSalsa20/Poly1305 ، xSalsa20/Poly1305 كبيرة بما يكفي - 192 بت. ومع ذلك ، فإن نقص AD هو قيد كبير.

عند استخدام Libsodium.NET ، تنشأ بعض الأسئلة. على سبيل المثال ، ما الذي يجب أن نفعله بالتحديد مع nonce الذي تم إنشاؤه بواسطة السطر الأول من التعليمات البرمجية في الأمثلة أعلاه؟ لا تخبرنا المكتبة شيئًا عن هذا ، علينا أن نكتشفها بمفردنا. على الأرجح ، سنضيف هذه القيمة يدويًا إلى بداية أو نهاية نص التشفير. علاوة على ذلك ، قد يكون لدينا انطباع بأن AD في أول طريقتين يمكن أن يكون بأي طول. لكن في الواقع ، لا تدعم المكتبة م أكثر من 16 بايت - بعد كل شيء ، 16 بايت ستكون كافية للجميع ، أليس كذلك؟ دعنا ننتقل. ماذا يحدث مع أخطاء فك التشفير؟ في هذه المكتبة ، تقرر في هذه الحالات رمي ​​الاستثناءات. إذا تم انتهاك تكامل البيانات في بيئتك أثناء فك تشفير البيانات ، فسيكون لديك العديد من الاستثناءات التي يجب معالجتها. ماذا لو كان حجم مفتاحك ليس 32 بايت بالضبط؟ لا تخبرنا المكتبة بأي شيء عن هذا ، فهذه هي مشاكلك التي لا تهمها. موضوع آخر مهم هو إعادة استخدام صفائف البايت لتقليل الحمل على جامع القمامة في سيناريوهات مكثفة. على سبيل المثال ، في الكود رأينا صفيفًا أعاده المولد غير التابع لنا. لا أريد إنشاء مخزن مؤقت جديد في كل مرة ، ولكن لإعادة استخدام المخزن الحالي. هذا غير ممكن في هذه المكتبة ، سيتم إعادة إنشاء مجموعة من البايت في كل مرة.

باستخدام المخطط الذي رأيناه بالفعل ، سنحاول مقارنة خوارزميات Libsodium.NET المختلفة.



تستخدم الخوارزمية الأولى ، AES-GCM ، طولها 96 بت (عمود أصفر في الصورة). إنها أقل من 128 بت ، مما يخلق بعض الانزعاج ، ولكن ليس كبيرًا. العمود التالي أزرق ، وهذا هو المكان الذي تشغله علامة المصادقة ، مع AES-GCM هو 16 بايت أو 128 بت. يشير الرقم الأزرق الثاني ، بين قوسين ، إلى مقدار الإنتروبيا أو العشوائية الواردة في هذه العلامة - أقل من 128 بت. كم أقل - في هذه الخوارزمية يعتمد على مقدار البيانات المشفرة. كلما كان التشفير أكثر ، كلما كانت العلامة أضعف. هذا وحده من شأنه أن يثير الشكوك حول هذه الخوارزمية ، والتي ستزداد فقط إذا نظرنا إلى العمود الأبيض. تقول أن تكرار (تصادمات) اللاإرادة سيؤدي إلى تزييف جميع النصوص المشفرة التي تم إنشاؤها بواسطة المفتاح نفسه. إذا كان هناك ، على سبيل المثال ، 100 من نصوص التشفير الخاصة بك التي تم إنشاؤها بواسطة مفتاح مشترك في اثنين ، فهناك تضارب غير أساسي ، سيؤدي هذا الإجراء إلى تسرب داخلي لمفتاح المصادقة ويسمح للمهاجم بتزييف أي نص تشفير آخر تم إنشاؤه بواسطة هذا المفتاح. هذا قيد هام للغاية.

دعنا ننتقل إلى طريقة Libsodium.NET الثانية. كما قلت ، هنا للغير ، يتم استخدام مساحة صغيرة جدًا ، فقط 64 بت. تحتل العلامة 128 بت ، ولكنها تحتوي على 106 بت فقط من الإنتروبيا أو أقل ، وبعبارة أخرى ، أقل بكثير من مستوى الأمان البالغ 128 بت ، والذي يحاولون تحقيقه في معظم الحالات. أما بالنسبة للتزييف ، فإن الوضع هنا أفضل قليلاً من حالة AES-GCM. يؤدي تصادم اللاخط إلى تزييف النصوص المشفرة ، ولكن فقط لتلك الكتل التي حدثت فيها التصادمات. في المثال السابق ، كنا سنزور نصين مشفرة ، وليس 100.

أخيرًا ، في حالة خوارزمية xSalsa / Poly ، لدينا عدد كبير جدًا من 192 بت ، مما يجعل التصادمات غير مرجحة للغاية. طريقة المصادقة هي نفسها كما في الطريقة السابقة ، لذا فإن العلامة تأخذ 128 بت مرة أخرى ولديها 106 بت من إنتروبيا أو أقل.

قارن كل هذه الأرقام بالمؤشرات المقابلة لمكتبة جحيم . في ذلك ، تحتل nonce مساحة هائلة ، 320 بت ، مما يجعل التصادمات شبه مستحيلة. أما بالنسبة للعلامة ، فكل شيء بسيط معها: فهي تحتل 128 بت بالضبط ولديها 128 بت من الكون تمامًا. هذا مثال لنهج موثوق وآمن.

قبل أن نتعرف على Libsodium.NET بمزيد من التفصيل ، نحتاج إلى فهم الغرض منه - للأسف ، ليس كل من يستخدم هذه المكتبة على علم به. للقيام بذلك ، ارجع إلى وثائقه ، التي تنص على أن Libsodium.NET عبارة عن غلاف C # لـ libsodium . هذا هو مشروع آخر مفتوح المصدر ، تشير وثائقه إلى أنه شوكة من NaCl مع واجهة برمجة تطبيقات متوافقة. حسنًا ، انتقل إلى توثيق NaCl ، وهو مشروع آخر مفتوح المصدر. كهدف ، يفترض NaCl لتوفير جميع العمليات اللازمة لإنشاء أدوات تشفير عالية المستوى. هنا تم دفن الكلب: مهمة NaCl وكل قذائفه هي توفير عناصر منخفضة المستوى ، يمكن من خلالها لشخص آخر تجميع واجهات برمجة تطبيقات تشفير عالية المستوى. لم يتم تصور هذه الأصداف نفسها كمكتبات عالية المستوى. ومن هنا الأخلاقي: إذا كنت بحاجة إلى واجهة برمجة تطبيقات تشفير عالية المستوى ، فأنت بحاجة إلى العثور على مكتبة عالية المستوى ، وعدم استخدام غلاف منخفض المستوى والتظاهر بأنك تعمل مع واحدة عالية المستوى.

دعونا نرى كيف يعمل التشفير في جحيم .



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

بدافع الاهتمام ، دعنا نحاول تشفير بعض السلسلة. يجب أن يكون هذا أبسط سيناريو يمكن للجميع تنفيذه. لنفترض أن لدينا فقط قيمتين مختلفتين للسلسلة: "LEFT" و "RIGHT".



في الصورة ، ترى تشفير هذه الخطوط باستخدام Inferno (على الرغم من أن هذا المثال لا يهم أي مكتبة يتم استخدامها). نقوم بتشفير خطين بمفتاح واحد ونحصل على نصين مشفرين ، c1 و c2 . هل كل شيء في هذا الرمز صحيح؟ هل هو جاهز للإنتاج؟ قد يقول شخص ما أن المشكلة ممكنة بطريقة قصيرة ، لكنها بعيدة عن المشكلة الرئيسية ، لذلك سنفترض أن المفتاح هو نفسه وأنه طويل بما فيه الكفاية. أعني شيئًا آخر: مع طرق التشفير التقليدية ، فإن c1 في مثالنا سيكون أقصر من c2 . ويسمى هذا تسرب طول - c2 في كثير من الحالات سيكون بايت واحد أطول من c1 . قد يسمح هذا للمهاجم بفهم السلسلة التي يمثلها هذا النص المشفر "LEFT" أو "RIGHT". أسهل طريقة لحل هذه المشكلة هي جعل كلا الخطين لهما نفس الطول - على سبيل المثال ، أضف حرفًا إلى نهاية سطر "LEFT".

للوهلة الأولى ، يُنظر إلى التسرب المطول على أنه مشكلة بعيدة المنال إلى حد ما لا يمكن مواجهتها في التطبيقات الحقيقية. ولكن في يناير 2018 ، تم نشر مقال في مجلة Wired مع دراسة أجرتها شركة Checkmarx الإسرائيلية ، تحت عنوان "عدم وجود تشفير في Tinder يسمح للأجانب بالتتبع عند تمرير الشاشة". سأذكر المحتوى لفترة وجيزة ، ولكن أولاً وصف تقريبي لوظيفة Tinder. Tinder هو تطبيق يتلقى دفقًا بالصور ، ثم يمرر المستخدم الشاشة يمينًا أو يسارًا ، اعتمادًا على ما إذا كان يحب الصورة أم لا. وجد الباحثون أنه على الرغم من تشفير الأوامر نفسها بشكل صحيح باستخدام TLS و HTTPS ، فإن بيانات الأمر الأيمن أخذت عددًا مختلفًا من البايت عن البيانات الموجودة على اليسار. هذه ، بالطبع ، نقطة ضعف ، ولكنها في حد ذاتها ليست كبيرة. كان الأمر الأكثر أهمية بالنسبة إلى Tinder حقيقة أنهم أرسلوا التدفقات مع الصور عبر HTTP العادي ، دون أي تشفير. لذلك يمكن للمهاجم الوصول ليس فقط إلى ردود فعل المستخدم على الصور ، ولكن أيضًا إلى الصور نفسها. لذا ، كما ترون ، يعد تسرب الطول مشكلة حقيقية للغاية.

الآن دعنا نحاول تشفير الملف. يجب أن أقول على الفور أنه في تشفير ملف Libsodium.NET أو ، على نطاق أوسع ، لا يتم تنفيذ تشفير الدفق افتراضيًا ، يجب القيام به هناك يدويًا - وهو ما يعتقد أنه من الصعب جدًا القيام به بشكل صحيح. في جحيم ، الأمور أفضل بكثير مع هذا.



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

يجب أن نتذكر أنه عند التشفير بنفس المفتاح ، لدينا حد لعدد الرسائل. توجد في جحيم ، وفي هذه المكتبة مكتوبة بوضوح على الشاشة. ولكن في نفس الوقت ، فهي كبيرة جدًا في الجحيم لدرجة أنك لن تصل إليها أبدًا. في Libsodium.NET ، تختلف القيود باختلاف الخوارزميات ، ولكنها في جميع الحالات منخفضة بما يكفي ليتم تجاوزها. لذلك تحتاج إلى التحقق مما إذا كان سيتم تحقيقها في كل سيناريو فردي.

يجب أن نتحدث أيضًا عن مصادقة البيانات المرتبطة ، لأن هذا موضوع لا يتم تناوله غالبًا. يمكن أن تكون الإعلانات "ضعيفة": وهذا يعني أنها مصادق عليها ، ولكنها لا تشارك في عملية التشفير وفك التشفير. في المقابل ، فإن الإعلانات "القوية" تغير هذه العملية نفسها. معظم مكتبات AD التي أعرفها ضعيفة ، بينما يستخدم Inferno النهج الثاني ، حيث يتم استخدام الإعلانات في عملية التشفير / فك التشفير نفسها ...

يجب أن يتطرق أيضًا إلى مستوى الأمان الذي يجب أن يسعى إليه من أجل التشفير عالي المستوى. باختصار ، إجابتي هي: تشفير 256 بت مع علامة مصادقة 128 بت. لماذا المفتاح كبير للغاية؟ هناك العديد من الأسباب لذلك ، كل منها مهم في حد ذاته ، ولكن الآن أود منك أن تتذكر شيئًا واحدًا: نحن بحاجة إلى حماية أنفسنا من التحيز المحتمل عند إنشاء مفاتيح التشفير. اسمحوا لي أن أشرح ما هو التحيز. بالنسبة لمولد بت عشوائي بدون تحيز ، لكل بت ، تكون احتمالات قبول القيمة 0 أو 1 متساوية. ولكن لنفترض أن البت في المولد سيأخذ القيمة 1 باحتمالية 56٪ وليس 50٪. للوهلة الأولى ، هذا التحيز صغير ، لكنه في الواقع مهم: 25٪. الآن دعنا نحاول حساب مقدار الإنتروبيا الذي نحصل عليه عند إنشاء عدد معين من البتات باستخدام المولد.



في الصورة ، ترى الصيغة التي سيتم بها إجراء هذا الحساب. من المهم أن يكون هناك متغيرين فقط فيهما: التحيز الذي تحدثنا عنه بالفعل (التحيز) ، وعدد البتات التي تم إنشاؤها بواسطة المولد. نفترض أن التحيز هو 25 ٪ - هذه حالة متطرفة إلى حد كبير ، في الممارسة العملية على الأرجح لن تعمل في الأنظمة التي تحتوي على مثل هذا الرقم العشوائي المشوه. على أي حال ، مع انحياز 25٪ ومفتاح 128 بت ، نحصل على 53 بت فقط من الإنتروبيا. أولاً ، إنها أقل بكثير من 128 بت ، والتي عادة ما تكون متوقعة من مولد رقم عشوائي ، وثانيًا ، مع التقنيات الحديثة ، يمكن أن يكون هذا المفتاح ببساطة القوة الغاشمة. ولكن إذا استخدمنا 256 بت بدلاً من مفتاح 128 بت ، فإننا نحصل على 106 بت من الكون. هذا جيد بالفعل ، على الرغم من أنه أقل من المتوقع 256. مع التقنيات الحديثة ، يكاد يكون من المستحيل كسر مثل هذا المفتاح.

في نهاية الجزء الأول من التقرير سأوجز النتائج المؤقتة. أوصي الجميع باستخدام واجهات برمجة تطبيقات التشفير المكتوبة بشكل جيد. اعثر على ما يناسبك ، أو أرسل عريضة إلى Microsoft لمراسلتك. بالإضافة إلى ذلك ، عند اختيار API ، يجب الانتباه إلى توفر الدعم للعمل مع سلاسل الرسائل. للأسباب التي سبق شرحها ، يجب أن يكون الحد الأدنى لطول المفتاح 256 بت. أخيرًا ، يجب أن يوضع في الاعتبار أن التشفير عالي المستوى ، مثل أي تشفير آخر ، ليس مثاليًا. يمكن أن تحدث التسريبات ، وفي معظم السيناريوهات يجب مراعاة قدراتها.

دعونا نتحدث عن التشفير غير المتماثل أو الهجين. سأطرح سؤال خدعة: هل يمكنك استخدام RSA في .NET؟ لا تتسرع في الإجابة بالإيجاب ، كما يفعل الكثيرون - دعنا أولاً نختبر معلوماتك في هذا المجال. سيتم تصميم الشرائح التالية خصيصًا للأشخاص المعتادين بالفعل على هذا الموضوع. ولكن أولاً ، دعنا نلقي نظرة على ويكيبيديا ، وتذكر ما هو RSA بالضبط في حالة نسي أحد الأشخاص أو لم يستخدم هذه الخوارزمية لفترة طويلة.



افترض أن هناك بعض أليس ، باستخدام مولد أرقام عشوائي ، يقوم بإنشاء زوج مفاتيح يتضمن واحدًا خاصًا وآخر عامًا. بعد ذلك ، هناك بعض الأشخاص الذين يريدون تشفير رسالة لـ Alice: "Hello Alice!" باستخدام مفتاحها العام ، يولد نصًا مشفرًا يرسله إليه بعد ذلك. تقوم بفك تشفير هذا النص المشفر باستخدام الجزء الخاص من مفتاحها.

دعونا نحاول إعادة إنتاج هذا السيناريو عمليًا.



كما ترى أعلاه ، نقوم بإنشاء مثيل من RSA وتشفير بعض النص. انتبه على الفور إلى أن .NET تجبرنا على اختيار وضع الحشو. هناك خمسة منهم بأسماء غامضة. إذا جربناها جميعًا بدورها ، فسوف نكتشف أن الثلاثة الأخيرة ببساطة ترمي استثناء ولا تعمل. سنستخدم أحد المتبقيين - OaepSHA1 . هنا ، سيكون المفتاح 1 كيلوبايت ، وهو صغير جدًا بالنسبة لـ RSA ، وهو مفتاح متصدع عمليا. لذلك ، يجب علينا تعيين حجم المفتاح يدويًا. من الوثائق نتعلم أن هناك خاصية خاصة. .KeySize ، التي تتلقى أو تعيين حجم المفتاح.



للوهلة الأولى ، هذا هو بالضبط ما نحتاجه ، لذلك نكتب: rsa.KeySize = 3072 . ولكن إذا استرشدنا بالريبة المبهمة ، بعد ذلك ، تحققنا من حجم المفتاح الذي يساوي الآن ، اكتشفنا أنه لا يزال يستغرق 1 كيلو بايت. لا يهم ، سوف نتحقق من هذه المعلمة باستخدام طريقة WriteLine(rsa.KeySize) ، أو rsa.ExportParameters(false).Modulus.Length * 8 - في الحالة الأخيرة ، يتم تصدير المكون العام لمفتاح RSA ، لذلك نحتاج إلى الوسيطة "false". معامل هذا المفتاح هو صفيف ، والذي نضربه في 8 ونحصل على الحجم بالبتات - والذي سيكون مرة أخرى كيلو بايت واحد. كما ترى ، لا تزال هذه الخوارزمية مبكرة جدًا للإرسال إلى الإنتاج.

لن نضيع الوقت في معرفة سبب عدم عمل واجهة برمجة التطبيقات هذه ، بدلاً من ذلك ، جرب تنفيذ RSA آخر توفره Microsoft في .NET 4.6 ، أي تطبيق جديد تمامًا. يطلق عليه RSACng ، و Cng لتقف على التشفير الجيل القادم. رائع ، من لا يريد العمل مع أدوات الجيل التالي؟ بالتأكيد سنجد هنا حلاً سحريًا لجميع مشاكلنا.



نطلب نسخة من RSACng ، ونعين مرة أخرى ضبط حجم المفتاح على 3 كيلو بت ، والتحقق مرة أخرى من حجم المفتاح عبر WriteLine(rsa.KeySize) - WriteLine(rsa.KeySize) مرة أخرى أن حجم المفتاح لا يزال يساوي كيلو بايت واحد. بالإضافة إلى ذلك ، إذا طلبنا نوع الكائن الذي أنشأ المفتاح - كما نذكر ، طلبنا مثيل من RSACng - فإننا نكتشف أنه RSACryptoServiceProvider. أريد فقط أن أشارك شعوري باليأس هنا ، وأصرخ ، "لماذا ، مايكروسوفت؟!"

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



هنا القيمة الافتراضية لحجم المفتاح هي 2048 بت ، وهي بالفعل أفضل بكثير. ما هو أفضل - هنا تمكنا أخيرًا من تعيين حجم المفتاح إلى 3 كيلو بت. كما يقولون ، فتح الإنجاز.

دعني أذكرك بأن جميع جهودنا حتى الآن تم تخفيضها فقط إلى إنشاء RSA ، لم نبدأ حتى في التشفير حتى الآن. لا تزال هناك أسئلة نحتاج إلى الإجابة عليها أولاً. بالنسبة للمبتدئين ، إلى أي مدى يمكنك الاعتماد على أحجام المفاتيح الافتراضية؟ قد يتم تجاوز تنفيذ مصنع RSA في machine.config، لذلك ، قد يتغير دون علمك (على سبيل المثال ، قد يقوم مسؤول النظام بتغييره). وهذا يعني أن حجم المفتاح الافتراضي يمكن أن يتغير أيضًا. وبالتالي ، يجب ألا تثق مطلقًا بالقيم المقدمة افتراضيًا ، ويجب دائمًا تعيين حجم المفتاح بشكل مستقل. بعد ذلك ، ما مدى جودة أحجام مفاتيح RSA الافتراضية؟ هناك نوعان من تطبيقات RSA في .NET ، أحدهما يستند RSACryptoServiceProviderإلى الآخرRSACng . 1 , . Bitcoin (BCN). , Bitcoin , . hashrate, 2 64 . 2 90 . , — , . , , , , 2 70 ( BCN) , 1- RSA, 2 90(سنة واحدة BCN) - لكسر مفتاح 2 كيلوبايت. يجب أن تسبب لنا كلتا القيمتين القلق - وهذا ما يمكن تحقيقه باستخدام التقنيات الحالية. لذلك أوصيك بشدة بتعيين حجم المفتاح بنفسك دائمًا ، وجعله لا يقل عن 3 كيلوبايت في الحجم ، وإذا كان الأداء يسمح لك ، فعندئذٍ 4.

في .NET ، ليس من السهل معرفة كيفية تصدير المفاتيح العامة والخاصة.



في الجزء العلوي من الشريحة ، ترى مثيلين من مفتاح RSA ، الأول من RSACryptoServiceProviderوالثاني منRSACngكل 4 كيلو بت. يستخدم الرمز أدناه لاستخراج المفاتيح العامة والخاصة من كلتا الحالتين. تجدر الإشارة إلى أن كلا APIs تختلف تمامًا عن بعضها البعض - رمز مختلف ، طرق مختلفة ، معلمات مختلفة. علاوة على ذلك ، إذا قارنا أحجام المفاتيح العامة للنسختين الأولى والثانية ، فسوف نرى أنها قابلة للمقارنة ، تقريبًا نصف كيلو بايت لكل منهما. لكن المفتاح الخاص لتطبيق RSA الجديد أصغر بكثير من المفتاح القديم. من الضروري وضع ذلك في الاعتبار وملاحظة التوحيد ، وليس التدخل في واجهات برمجة التطبيقات هذه مع بعضها البعض.

كل ما فعلناه مع RSA حتى الآن قد حان لمحاولة الحصول على نسخة عاملة ؛ حاول الآن تشفير شيء ما.



قم بإنشاء مجموعة من وحدات البايت ، والتي ستكون نصنا العادي (data) ، وبعد ذلك سنقوم بتشفيرها باستخدام أحد أوضاع الإضافة تلك التي لم تستثني. لكن هذه المرة لدينا استثناء. هذا استثناء لمعلمة غير صالحة ؛ ولكن ما هي المعلمة التي نتحدث عنها؟ ليس لدي أي فكرة - وعلى الأرجح ، فإن Microsoft أيضًا. إذا حاولنا تشغيل نفس الطريقة مع أوضاع مكملة أخرى ، فإننا نحصل في كل حالة على نفس الاستثناء. لذا فإن النقطة ليست في وضع المكمل. لذا فإن المشكلة تكمن في شفرة المصدر نفسها. من الصعب أن نقول ما هو الخطأ معه ، لذلك دعونا نحاول تقطيعه إلى النصف فقط في حالة. هذه المرة ، ينجح التشفير. نحن في حيرة.

ربما كانت النقطة الأساسية هي أننا استخدمنا ملحق SHA-1؟ SHA-1 ، كما نعلم ، لم تعد وظيفة قوية في التشفير ، لذا يصر مراجعو الحسابات وإدارة الامتثال على التخلص منها. استبدال OaepSHA1على OaepSHA256، على الأقل سيكون تهدئة مراجعي الحسابات.



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

دعنا نحاول معرفة كيف تبدو هذه الصيغة السحرية بالضبط ، والتي تحدد الحد الأقصى من البيانات المشفرة. يجب أن يكون في الطريقةint GetMaxDataSizeForEnc(RSAEncryptionPadding pad)، الذي يحسب هذا الحجم ، بعد تلقي وضع المكمل عند الإدخال. العيب الرئيسي لهذه الطريقة هو أنها غير موجودة ، اخترعتها. أحاول إيصال فكرة أنه حتى المعلومات الأساسية التي يحتاجها المطور لاستخدام RSA بشكل صحيح ليست متاحة لنا. شكرا مايكروسوفت.

فيما يلي أسباب وجوب تجنب RSA ، حتى للتوقيع. كما أتمنى أن أتمكن من العرض ، فإن واجهات برمجة التطبيقات لـ RSA في .NET غير مرضية للغاية. أنت مجبر على اتخاذ العديد من القرارات فيما يتعلق بوضع المكمل وحجم البيانات وما شابه ، وهو أمر غير مرغوب فيه. علاوة على ذلك ، للحصول على مستوى أمان 128 بت ، ستحتاج على الأقل إلى مفتاح كبير جدًا بحجم 4 كيلوبايت. سيعطيك مفتاح خاص كيلوبايت ، ومفتاح عام نصف كيلوبايت ، وتوقيع نصف كيلوبايت. بالنسبة للعديد من السيناريوهات ، قد لا تكون هذه القيم مرغوبة. وإذا حاولت تحقيق مستوى أمان 256 بت ، فستحتاج إلى مفتاح ضخم على الإطلاق - 15360 بت. يكاد يكون من المستحيل استخدام مثل هذا المفتاح في RSA. على جهاز الكمبيوتر المحمول الخاص بي يتم إنشاء مثل هذا المفتاح دقيقة ونصف.بالإضافة إلى ذلك ، تقوم RSA على مستوى أساسي ، كخوارزمية ، بتنفيذ توقيع ببطء شديد ، بغض النظر عن التنفيذ. لماذا تعد سرعة التوقيع مهمة بالنسبة لنا؟ إذا كنت تستخدم TLS مع شهادات RSA ، فسيتم التوقيع على الخادم. ونحن كمطورين نتأثر أكثر بما يحدث بالضبط على الخادم ، نحن مسؤولون عنه ، إنتاجيته مهمة بالنسبة لنا. باختصار ، أود أن أوصي مرة أخرى بعدم استخدام RSA.أريد أن أوصي مرة أخرى بعدم استخدام RSA.أريد أن أوصي مرة أخرى بعدم استخدام RSA.

في هذه الحالة ، ما الذي يمكن أن يحل محل RSA؟ أود أن أقدمك إلى البدائية التشفير البيضاوية الحديثة. بادئ ذي بدء ، يجب أن تضع في اعتبارك ECDSA (خوارزمية التوقيع الرقمي) ، والتي يمكن استخدامها بدلاً من RSA للتوقيعات. في هذا والاختصارات التالية ، EC هي بادئة عامة تشير إلى المنحنى البيضاوي ("البيضاوي"). في securitydriven.net/inferno/#DSA تواقيع ، يمكنك العثور على عينة كود ECDSA ، والتي ، بالمناسبة ، هي أصلية في .NET. خوارزمية مهمة أخرى هي ECIES (مخطط التشفير المتكامل ، "مخطط التشفير المتكامل البيضاوي"). يمكن لهذه الخوارزمية إجراء تشفير مختلط بدلاً من RSA ، حيث تقوم بإنشاء مفتاح متماثل ، وتشفير البيانات به ، ثم تشفير المفتاح نفسه.نموذج التعليمات البرمجية متاح في securitydriven.net/inferno/#ECIES المثال. وأخيرًا ، هناك خوارزمية أخرى مهمة للغاية وهي ECDH (تبادل مفاتيح Diffie-Hellman ، "تبادل مفاتيح Diffie-Hellman"). يسمح لك بإنشاء مفاتيح للتشفير المتماثل بين طرفين باستخدام مفاتيح عامة معروفة. في بعض الحالات وطرق الاستخدام ، يسمح بالسرية المباشرة (السرية إلى الأمام ). الرابط securitydriven.net/inferno/#DHM مفتاح للأوراق نموذج التعليمات البرمجية المتاحة.

لتلخيص الحديث عن التشفير غير المتماثل. يجب عليك دائمًا استخدام واجهات برمجة التطبيقات عالية المستوى التي لا تجبرك على اتخاذ قرارات لست مستعدًا لها. أوصي أيضًا بالتوقف عن استخدام RSA. بالطبع ، هذا قول أسهل من الفعل ، لأننا جميعًا نعمل مع تطبيقات كبيرة تم إنشاؤها بالفعل ، والتي قد لا يتم إعادة هيكلتها بالكامل. في هذه الحالة ، تحتاج على الأقل إلى معرفة كيفية استخدام RSA بشكل صحيح. علاوة على ذلك ، أنصحك بالتعرف على خوارزميات التشفير الإهليلجية الحديثة (ECDSA ، ECDH ، ECIES). أخيرًا ، من المهم ألا يحل التشفير عالي المستوى جميع المشكلات بطريقة سحرية ، لذلك تحتاج إلى تذكر الأهداف التي تسعى إليها. سأقتبس من StackOverflow ، والذي أتفق معه تمامًا: "التشفير وحده لا يحل المشاكل.يجعل التشفير المتماثل خصوصية البيانات مشكلة إدارة رئيسية فقط. "

سأقول بضع كلمات عن الموارد التي قد تكون مفيدة لك. هناك مكتبة SecurityDriven.Inferno عالية المستوى مقبولة نسبيًا مع وثائق جيدة. هناك كتاب رائع ، تشفير خطير من تأليف جان فيليب أوماسون ، تشفير خطير. يوفر نظرة عامة على الوضع الحالي للتشفير ، مع مراعاة أحدث الابتكارات. بالإضافة إلى ذلك ، كتبت الكتاب المذكور مسبقًا Application Security في .NET ، بإيجاز ، الموجود في المجال العام. لديها المزيد من المعلومات حول مصائد أمان .NET. أخيرًا ، يحتوي Slideshare على عرض تقديمي ممتاز من قبل فلاديمير كوتشيتكوف ، والذي يوجز أساسيات نظرية أمان التطبيقات بطريقة بسيطة إلى حد ما ولكن متينة للغاية ويشرح المصادر المختلفة للمخاطر.

في الختام ، دعنا نرى بعض الأمثلة الإضافية التي أعددتها. في البداية ، تحدثت عن المرحلة الرابعة من التنوير المشفر ، حيث يتعلق الأمر بإدراك أن أفضل حل قد لا يحتاج إلى التشفير على الإطلاق. دعونا نلقي نظرة على مثال لهذا الحل. دعنا نلقي نظرة على آلية .NET الكلاسيكية - CSRF (تزوير طلب المواقع المشتركة ، "تزوير طلب المواقع المشتركة") ، المصممة للحماية من فئة الهجمات ، بما في ذلك تزوير طلبات المواقع المشتركة. في هذا النموذج ، لدينا وكيل مستخدم - عادةً متصفح. يحاول إنشاء اتصال بالخادم عن طريق إرسال طلب GET. واستجابة لذلك ، يرسل الخادم رمز CSRF مخفيًا في حقل HTML "المخفي". بالإضافة إلى ذلك ، يتم إرفاق نفس الرمز المميز بالرد كملف تعريف ارتباط ، كعنوان.يقوم المستخدم بمعالجة بعض النماذج ويقوم بإجراء POST ، والذي يعود إلى الخادم بكل من الرموز المميزة. يتحقق الخادم ، أولاً ، مما إذا كان كلا الرمزين تم إرسالهما ، وثانيًا ، ما إذا كانا متطابقين. إن مقارنة الهوية هذه هي التي تسمح للخادم بحماية نفسه من المهاجم. هذه آلية كلاسيكية مضمنة في ASP.NET و ASP.NET Core. قدم Mikhail Shcherbakov تقريرًا ممتازًا تم فيه التحقيق في عمل CSRF بالتفصيل.

المشكلة في هذا الأسلوب هي أن إنشاء الرمز المميز لـ CSRF يستخدم التشفير. تكمن الصعوبة في أن التشفير في حد ذاته عملية معقدة وتستهلك الموارد ، فهو يقوم بتحميل المعالج ، ويتطلب ذاكرة ، ويزيد من التأخير. كل هذا غير مرغوب فيه. بالإضافة إلى ذلك ، يعد حقن الرمز المميز عملية مرهقة ومربكة وغير ملائمة. في كثير من الحالات - على سبيل المثال ، عند استخدام AJAX والمكالمات غير المتزامنة - يقع تنفيذها عليك كمطورين. أولئك الذين فعلوا ذلك يعرفون أن هذا النشاط مزعج للغاية.



يمكن إنشاء الحماية التشفيرية نفسها أو القابلة للمقارنة دون استخدام التشفير ، كما هو موضح على الشريحة. أفهم أن النص هنا معقد للغاية ، لذا فأنا مستعد لمناقشته بمزيد من التفصيل في مجال المناقشة. هذا كل شيء بالنسبة لي ، شكرا جزيلا.

. DotNext. DotNext 2018 Moscow — 22-23 2018 - « ».

. , , . ! .

Source: https://habr.com/ru/post/ar428121/


All Articles