پایتون مجبوبترین زبان برنامهنویسی حال حاضر است که قابلیت استفاده در انواع مختلفی از پروژهها را دارد. در شرایطی که زبانهای برنامهنویسی سطح پایین مثل سی یا سیپلاسپلاس با انواع مختلفی از مشکلات روبرو هستند، در نقطه مقابل برنامهنویسان پایتون چنین مشکلی را ندارند. به طور مثال، در پایتون با مدیریت درست حافظه مانع از آن میشود تا مشکلاتی مثل نشت حافظه و سرریز بافر عملکرد برنامهها را متوقف کند.
پیشنهاد مقاله: آیا برای یادگیری برنامهنویسی شرط سنی خاصی وجود دارد؟
پایتون از مکانیزمهای پیشرفتهای مثل garbage collection برای آزادسازی حافظه اختصاص یافته به اشیا استفاده میکند. با این حال، پایتون بدون مشکل نیست و آسیبپذیریهای خاص خود است که با رعایت چند نکته ساده به سادگی قادر به عبور از این مشکلات هستید.
هنگام توسعه نرمافزارهای کاربردی، کدنویسی امن (Secure Coding) برای محافظت از دادههای حساس و حفظ عملکرد درست نرمافزار، ضروری است. درست است که کدنویسی امن پیچیده و وقتگیر است و حتی بهترین توسعهدهندگان نیز نمیتوانند کدهایی با امنیت بالا را طراحی کنند، اما این امکان وجود دارد تا بر مبنای برنامهنویسی درست مانع بروز برخی از مشکلات رایج شد.
مهم نیست برنامه چقدر کوچک است یا توسعهدهندگان چقدر در کار خود خوب هستند، همیشه احتمال بروز مشکلات و آسیبپذیریهای امنیتی وجود دارد که اجازه میدهند هکرها به شیوههای مختلف از آسیبپذیریها برای ضربه زدن به کاربران استفاده کنند.
برای پیشگیری از بروز مشکلات امنیتی چه اقداماتی باید انجام داد؟
بهترین کاری که میتوان انجام داد این است که هنگام توسعه برنامهها با استفاده از زبان برنامه نویسی پایتون از بهترین الگوها برای کدنویسی امن استفاده کنیم. در این مقاله، به مهمترین راهکارها و راهحلهایی که برای ایمنسازی و کدنویسی کارآمد در اختیار برنامهنویسان قرار دارد، اشاره خواهیم کرد.
1- از جدیدترین نسخه زبان برنامه نویسی پایتون استفاده کنید
بیشتر شرکتها و توسعهدهندگان هنوز هم از نسخههای قدیمی پایتون مثل Python 2.6 یا Python 2.7 برای توسعه برنامههای کاربردی استفاده میکنند. نکته مهمی که باید به آن دقت کنید این است که نسخههای مذکور بعد از آوریل 2020 دیگر بهروزرسانی امنیتی دریافت نکردهاند.
پایتون 3 در سال 2008 منتشر شد و از ابتدای ژانویه 2020 بنیاد پایتون اعلام کرد که پایتون 2، دیگر بهروزرسانیهای امنیتی یا پشتیبانی را دریافت نخواهد کرد. اگر هنوز از نسخههای قدیمی پایتون استفاده میکنید، باید به فکر انتقال پروژههای خود به پایتون 3 باشید. بهتر است از پایتون 3 برای پروژههای جدید استفاده کنید. در صورت عدم توجه به این هشدار باید آمادگی رویارویی با آسیبپذیریهای امنیتی را داشته باشید. برای بررسی نسخه پایتون خود، میتوانید کد زیر را در کنسول اجرا کنید:
python –version
همچنین از کانتینرهای رسمی طراحی شده برای اجرای پایتون استفاده کرده و آنها را بهروز نگه دارید.
2. از محیط مجازی استفاده کنید
هنگامی که روی پروژههای پایتون کار میکنید، پیشنهاد ما این است که از یک محیط مجازی (Virtual Environment) استفاده کنید، زیرا مانع بروز مشکل عدم هماهنگی ماژولهای پایتون میشود. همچنین، بهتر است از ماژولهای یکسانی در محیطهای محلی و تولیدی استفاده کنید.
پایتون قابلیت خوبی در ارتباط با توسعه برنامهها در محیطهای مجازی در اختیار توسعهدهندگان قرار میدهد. یک محیط مجازی مفسر پایتون مجهز به کتابخانهها و اسکریپتهای نصب شده است. به بیان دقیقتر، به جای استفاده از نسخه global پایتون و وابستگیهای global پایتون در ارتباط با پروژههای خود، میتوانید محیطهای مجازی خاصی برای پروژهها داشته باشید و از نسخههای پایتون و وابستگیهای آن استفاده کنید.
محیطهای مجازی، فرآیندهای توسعه، بستهبندی و ارسال برنامههای کاربردی امن برای پایتون را سادهتر میکنند. اگر بستههای مشکوک به خطایی در برنامه پایتون دارید، به کارگیری یک محیط مجازی، مانع از آن میشود تا وابستگیهای مخرب به پروژهها و محصول نهایی وارد شوند. برای ساخت یک محیط مجازی میتوانید از ابزارهایی مثل Virtualenv یا Pipenv استفاده کنید که توانایی ساخت محیطهای مجازی ایزوله را ارائه میکنند.
با استفاده از Pipenv میتوانید نصابها و محیطهای مجازی را مدیریت کنید، درخت وابستگی را بررسی کنید و وابستگیها را به منظور شناسایی آسیبپذیریها، اسکن کنید. برای اجرای Virtualenv از دستورات زیر استفاده کنید.
pip install virtualenv
virtualenv -p /path/to/python <env_name>
3. بستهها را به شیوه درست به پروژهها وارد کنید
هنگام کار با ماژولهای خارجی یا داخلی زبان برنامه نویسی پایتون، اطمینان حاصل کنید که به شیوه درستی به پروژهها وارد شدهاند و از مسیرهای مناسبی برای این منظور استفاده کردهاید. ما دو نوع مسیر برای وارد کردن بستهها در پایتون داریم که مطلق و نسبی هستند.
Importهای مطلق، مسیر منبعی که قرار است وارد شود از پوشه ریشه پروژه مشخص میکنند، در نقطه مقابل در import نسبی، منبعی که باید وارد شود نسبت به مکان فعلی پروژه، جایی که عبارت import استفاده میشود، مشخص میشود. برای روشن شدن بحث به شبه دستورات زیر دقت کنید:
/* Absolute Import */
from package1 import module1
from package1.module2 import function1
/* Relative Import */
from .some_module import some_class
from ..some_package import some_function
در وارد کردن نسبی بستهها دو گزینه ضمنی و صریح (implicit and explicit) در اختیار توسعهدهندگان قرار دارد.
وارد کردن صریح (Implicit imports) مسیر منبع را نسبت به ماژول فعلی تعیین نمیکند، در نقطه مقابل در وارد کردن ضمنی (Explicit imports) مسیر دقیق ماژولی که میخواهید وارد کنید نسبت به ماژول فعلی تعیین میشود.
در پایتون نسخه سوم، وارد کردنهای ضمنی حذف شدند، زیرا اگر ماژول مشخص شدهای در مسیر سیستم پیدا شود، میتواند به پروژه وارد شود و این مسئله به لحاظ امنیتی دردسرآفرین است.
با توجه به اینکه ممکن است یک ماژول مخرب با نام یکسان در یک کتابخانه منبع باز وجود داشته باشد و راه خود را به مسیر سیستم پیدا کند، اگر ماژول مخرب قبل از ماژول واقعی پیدا و وارد شد، به هکرها اجازه میدهد از برنامه کاربردی برای مقاصد مخرب استفاده کنند.
برای پیشگیری از بروز چنین مشکلی، اطمینان حاصل کنید از importهای مطلق یا importهای نسبی صریح استفاده میکنید. رویکرد فوق تضمین میکند که همواره ماژول واقعی پیدا و به پروژه افزوده میشود.
from safe_module import package, function, class
یا
from ..relative_module import package, function, class
اگر هنوز از پایتون نسخه دو استفاده میکنید، اطمینان حاصل کنید importهای نسبی ضمنی را حذف کردهاید، زیرا اگر پروژه را به نسخه 3 سوییچ کنید، پایتون پیغام خطایی در این زمینه نشان میدهد.
پیشنهاد مقاله: بهترین کتابخانه های پایتون برای یادگیری ماشین + نمونه کدهای عملی
4. مراقب بستههای مخرب باشید
بستهها میتوانند بسیار مفید باشند و به برنامهنویسان اجازه میدهند در مدت زمان کوتاهتری پروژهها را به سرانجام برسانند. بستهها را میتوان به راحتی از طریق ابزار مدیریت بسته Pip نصب کرد. آنها مزایای مختلفی مانند صرفهجویی در زمان، فشردگی و کوچکتر پروژههای کاربردی را به ارمغان میآورند، رویکردی که در نهایت بهبود عملکرد برنامهها را به همراه دارد. بیشتر بستههای پایتون در PyPI منتشر میشوند که به عنوان یک مخزن کد برای بستههای پایتون عمل میکند و هیچ گونه بررسی امنیتی در ارتباط با آنها انجام نمیشود.
این حرف بدان معنا است که هر کسی که نیت بدی داشته باشد، میتواند به راحتی بستهای را با کد مخرب در PyPI بسازد و منتشر کند یا گاهی اوقات بستهای را با نامی مشابه با یک بسته محبوب منتشر کند و از ویژگیهای بسته تقلید کند. هر بسته پایتونی را که نصب و به پروژه اضافه میکنید را به دقت بررسی کنید تا مطمئن شوید اکسپلویتهایی در برنامه شما وارد نشده باشد. همچنین، میتوانید از ابزارهای امنیتی برای اسکن وابستگیهای پایتون خود و غربالگری آنها استفاده کنید.
به خاطر داشته باشید بستههایی که میتوانند از طریق PyPI نصب شوند، همیشه برای بدافزار اسکن نمیشوند. این مسئولیت شما است که قبل از استفاده به طور کامل بررسی کنید که آیا هر چیزی که نصب کردهاید واقعا ایمن است یا خیر.
5. قالببندی رشتهها در پایتون
پایتون یکی از قدرتمندترین و انعطافپذیرترین روشها را برای قالببندی رشتهها ارائه میکند، اما اگر در حین استفاده دقت کافی نداشته باشید، ممکن است در نهایت یک آسیبپذیری امنیتی در کد خود ایجاد کنید. پایتون نگارش سه، f-strings و str.format را به عنوان روشهایی انعطافپذیر برای قالببندی رشتهها در دسترس توسعهدهندگان قرار دارند که قابلیتهای خوبی در اختیار آنها قرار میدهند. با این حال، راه را برای سوء استفاده از دادهها در هنگام تعامل با ورودیهای کاربر به وجود میآورند. اگر برنامه ساخته شده با پایتون به کاربران اجازه کنترل قالببندی رشتهها را بدهد، این امکان فراهم میشود که از این تکنیک برای استخراج اطلاعات حساس استفاده کرد. برای روش شدن بحث به مثل زیر دقت کنید:
CONFIG = {
“API_KEY”: “secret_key”
}
class User:
name = “”
email = “”
def __init__(self, name, email):
self.name = name
self.email = email
def __str__(self):
return self.name
name = “Hamid”
email = “HamidRRT@protonmail.com”
user = User(name, email)
print(f”{user.__init__.__globals__[‘CONFIG’][‘API_KEY’]}”)
/* secret_key */
با این کار، دادههای حساس سراسری از لغتنامه به نام CONFIG، از طریق آرگومان قابل دسترسی هستند. با این حال، پایتون یک ماژول string داخلی دارد که میتواند برای جلوگیری از بروز این مشکل استفاده شود. برای این منظور از کلاس Template از ماژول string به شرح زیر استفاده کنید:
from string import Template
name_template = Template("Hello, my name is $name.")
greeting = name_template.substitute(name="Hamid")
/* Hello, my name is Hamid */
این ماژول string برای مدیریت ورودیهای کاربر و دادههای تولید شده، عملکرد خوبی دارد.
ماژول رشته برای مدیریت ورودیهای کاربر و دادههای تولید شده توسط او عملکرد خوبی دارد. پایتون چهار مکانیزم قالببندی رشته انعطافپذیر را ارائه میدهد. با این حال، نحو قالببندی انعطافپذیر مانند f-Strings میتواند در برابر اکسپلویتها آسیبپذیر باشد. به همین دلیل است که توسعهدهندگان باید هنگام قالببندی رشتههای تولید شده توسط کاربر به آنها دقت کنند. ماژول رشته داخلی پایتون میتواند به شما برای حل این مشکل کمک کند. ماژولهای رشته داخلی بر اساس کلاس الگو هستند که به شما امکان میدهد رشتههای الگو را ایجاد کنید. به عنوان مثال، کد زیر از کاربران میخواهد که نام خود را وارد کنند و سپس نام را نمایش میدهد:
from string import Template
name_template = Template(“Hello, my name is $name.”)
greeting = name_template.substitute(name=”Hamid”)
خروجی رشته “Hello, my name is Hamid” است. این ماژول رشتهای به اندازه f-string انعطافپذیر نیست. به همین دلیل است که ماژولهای رشتهای انتخاب خوبی برای مدیریت ورودیهای کاربر هستند.
6. درخواستهای HTTP پایتون را ایمن مدیریت کنید
هنگام ساخت پروژه پایتون که نیاز به ارسال درخواستهای HTTP دارد، همیشه توصیه میشود این کار را به شیوه مطمئن انجام دهید و اطمینان حاصل کنید کتابخانهای که از آن استفاده میکنید اصول امنیت را رعایت کرده است. هنگام استفاده از کتابخانه درخواستهای HTTP مانند Requests، نباید نسخههایی که ممکن است نسخه قدیمی و آسیبپذیر ماژول را نصب کنند، در applications.txt خود پین کنید.
به عنوان مثال، Requests از Certifi برای مدیریت تأیید SSL استفاده میکند، مطمئن شوید که آنرا به یک سایت غیر بهره برداری شده ارسال می کنید. بهطور پیشفرض، Requests تأیید گواهی SSL را کنترل میکند و در صورت اعتماد به منبع، میتواند غیرفعال شود.
url = “http://trusted_url”requests.get(url, safe=False)
رویکرد فوق تضمین میکند درخواستهایی به منبع مخرب ارسال نمیکنید که در نهایت کدهای مخرب را در سرآیندها یا بدنه Response ارسال کند.
بنابراین برای ارزیابی این مسئله مطمئن شوید که از آخرین نسخه کتابخانه HTTP requests استفاده میکنید. در صورتی که کتابخانه تایید SSL، منبعی را که درخواستها را به آن ارسال کردهاید، مدیریت میکند، آنرا ارزیابی کنید. همچنین، اگر از کتابخانه استاندارد urllib استفاده میکنید، باید بهترین متدها را برای جلوگیری از ارسال درخواست های غیر معتبر مورد استفاده قرار دهید.
7. کدهای خود را اسکن کنید
یک راه ساده برای یافتن آسیبپذیریهای امنیتی در کدهای پایتون، اجرای اسکن با Bandit است. Bandit یک پروژه متن باز است که از طریق فهرست PyPI در دسترس است. Bandit هر فایل پایتون که کدها درون آن قرار دارند را اسکن میکند و یک درخت نحو انتزاعی مربوطه (AST) میسازد. سپس، Bandit تعدادی پلاگین را روی AST اجرا میکند تا مشکلات امنیتی نرم افزاری رایج را پیدا کند.
به عنوان مثال، یک پلاگین میتواند تشخیص دهد که آیا از Flask (یک ریز چارچوب برای پایتون) با تنظیمات اشکالزدایی برابر با True استفاده میکنید یا خیر. Bandit یا به عنوان یک ابزار محلی برای استفاده در حین توسعه یا به عنوان بخشی از مکانیزم CI/CD (ادغام پیوسته/ تحویل مداوم) مورد استفاده قرار میگیرد. میتوانید یک فایل پیکربندی YAML ایجاد کنید تا نحوه رفتار Bandit در سناریوهای مختلف را کنترل کنید.
در این فایل شما میتوانید لیستی از تستهایی را که باید انجام شوند را مشخص کنید. البته دقت کنید که از روش فوق باید با احتیاط کامل استفاده کنید. هیچ تضمینی وجود ندارد که Bandit همه مشکلات امنیتی را برطرف کند، زیرا تعداد محدودی پلاگین وجود دارد که اجرا میکند و احتمالا ممکن است مشکلی در کدهای شما وجود داشته باشد که هیچ افزونهای اطلاعاتی در مورد آنها نداشته باشد. با این حال، استفاده از آن آسان است و یک رابط کاربری عالی برای نمایش مشکلات در اختیارتان قرار میدهد.
از ویژگیهای کلیدی Bandit باید به موارد زیر اشاره کرد:
- پلاگینهای تست: آزمایشهای مختلفی را انجام میدهند و به شما در تشخیص مسائل امنیتی در کدهای پایتون کمک میکنند.
- پلاگین های لیست سیاه: شما میتوانید importها و فراخوانیهای توابع مشکوک را در لیست سیاه قرار دهید. این قابلیت بخشی یکپارچه از یکی از تستهای Bandit است. شما میتوانید این تست را به شکل روتین مورد استفاده قرار دهید.
- فرمتکنندههای گزارش: از قالببندیهای مختلفی پشتیبانی میکند تا مشکلات امنیتی را در خروجی نشان دهد. میتوانید این قالبتبندیها را بهعنوان پلاگین ایجاد کنید و عملکرد Bandit را گسترش دهید. همچنین برخی ابزارها و اسکنرهای امنیتی مانند Pyntch، Spaghetti و Requires برای توسعه ایمن نرمافزارهای پایتون در دسترس هستند.
8. همیشه دادههایی که از منبع خارجی دریافت میشوند را ارزیابی و پالایش کنید
یکی از راههای حمله به برنامههای کاربردی از طریق دادههای است که از منابع خارجی دریافت میشوند و ممکن است راه را برای پیادهسازی انواع مختلفی از حملهها مثل SQL Injection، XSS یا انکار سرویس هموار کنند. یک قانون کلی در ارتباط با امنیت پایتون این است که همیشه دادههایی که از منابع خارجی میآید را پالایش کنید. همچنین، به محض ورود دادهها به برنامه، آنها را اعتبارسنجی کنید تا مانع بروز حمله به پایگاههای داده شوید.
9. مجوزهای وابستگی ها را مرور کنید
نکته دیگری که باید به آن دقت کنید این است که هنگام استفاده از یک پروژه منبع باز باید به آن دقت کنید این است که بدانید این پروژهها چگونه مجوز دریافت کردهاند. پروژههای منبع باز، رایگان و قابل استفاده هستند، اما ممکن است تحت شرایط و ضوابطی قابل استفاده باشند.
این شرایط به طور معمول شامل نحوه استفاده از نرمافزار، این که آیا نیاز به ایجاد هرگونه تغییری در نرمافزار هنگام استفاده عمومی از آن وجود دارد یا خیر و سایر الزامات مشابه است. شما باید از مجوزهای منبع باز مناسب در ارتباط با بستههایی که قصد استفاده از آنها را در پروژه خود دارید استفاده کنید.
برای اطمینان از این که پروژه شما پایدار است و مشکل امنیتی نخواهد داشت، مسائل مربوط به مجوز و آسیبپذیری در وابستگیهای پروژه را شناسایی و آنها را برطرف کنید.
10. با احتیاط از De)serialize) استفاده کنید
پیشنهاد میکنیم دادهها را از یک منبع قابل اعتماد deserialization کنید، زیرا ممکن است کدهای مخربی در دادهها مستتر باشد. اگر داده ها حاوی کد مخرب باشند، در صورت deserialization میتوانند کد را اجرا کنند و در نتیجه از دادههای کاربر سو استفاده کرده یا عملیات خطرناکتری را انجام دهند.
پایتون یک مکانیزم داخلی برای serialize و deserialize اشیا پایتون به نام pickling دارد. این مکانیزم غیر امن شناخته شده است و توصیه میشود از آن تنها در ارتباط با منابع داده قابل اعتماد استفاده کنید.
یکی از بهترین بستهها برای انجام چنین کارهایی PyCrypto است، زیرا دادههای شما را به طور ایمن deserialize میکند و از اجرای کد دلخواه جلوگیری میکند.
YAML نوع دیگری از انواع داده است که بیشتر برای پیکربندی دادهها استفاده میشود و با استفاده از بسته PyYAML مدیریت میشود. بسته PyYAML مکانیزمی را برای serialize انواع دادههای سفارشی به YAML و بازگشت دوباره فراهم می کند، اما PyYAML با انواع مختلفی از حمله های هکری روبرو است. یک راه ساده، اما موثر برای ایمنسازی استفاده از PyYAML، استفاده از ()yaml.SafeLoader به جای ()yaml.Loader به عنوان یک بارگذار است.
Data = yaml.load(input_file, Loader=yaml.SafeLoader)
این مکانیزم مانع بارگذاری کلاسهای سفارشی شده و از انواع استانداردها مانند هشها و آرایهها پشتیبانی میکند.
منابع:
https://snyk.io/blog/python-security-best-practices-cheat-sheet/
https://github.com/mjasaba/Securiry-Best-Practices-