12 نکته‌ی کدنویسی امن برای برنامه نویسان پایتون

12 نکته‌ی کدنویسی امن برای برنامه نویسان پایتون

بیشتر مسائلی که در زبان های سطح پایین رایج هستند، تاثیر کمتری در زبان برنامه نویسی پایتون (Python) دارند. برای مثال در پایتون اجتناب از مشکلاتی مانند نشت حافظه و سرریز بافر بسیار ساده تر است. زبان برنامه نویسی پایتون با ویژگی هایی مانند garbage collection، که به طور خودکار موارد قدیمی را از حافظه حذف می کند، از این مشکلات جلوگیری می کند. با این حال، دارای آسیب پذیری های خاص خود است که می‌توان با بهترین روش ها، آنها را برطرف کرد. 

هنگام توسعه ی نرم افزار، کدنویسی امن (Secure Coding) برای محافظت از داده های حساس و حفظ رفتار صحیح نرم افزار، ضروری است. اگر چه کدنویسی امن گاهی سخت است و حتی بهترین توسعه دهندگان نیز نمی توانند همیشه از امنیت کد خود 100% مطمئن باشند.  

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

برای جلوگیری از این اتفاق، چه کاری باید انجام داد؟ 

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

 

1- از آخرین نسخه اصلی پایتون استفاده کنید. 

بسیاری از شرکت ها و توسعه دهندگان هنوز نسخه های قدیمی پایتون را برای پروژه های خود، مانند Python 2.6 یا Python 2.7 اجرا می‌کنند. این ها نسخه ها بعد از آوریل 2020 دیگر به روز رسانی امنیتی دریافت نکردند. 

Python 3 در سال 2008 منتشر شد و از اول ژانویه 2020 بنیاد پایتون اعلام کرد که Python 2، دریافت به روز رسانی های امنیتی یا پشتیبانی را متوقف خواهد کرد. 

اگر هنوز از نسخه‌های قدیمی پایتون (زیر Python 3) استفاده می‌کنید، باید نحوه ی انتقال کد خود را به Python 3 در نظر بگیرید. از Python 3 برای پروژه های جدید خود استفاده کنید یا آماده ی پذیرش آسیب پذیری های امنیتی باشید. 

برای بررسی نسخه پایتون خود، می توانید کد زیر را در کنسول اجرا کنید:

python –version

 همچنین از کانتینرهای (containers) رسمی طراحی شده برای اجرای پایتون استفاده کرده و آن ها را به روز نگه دارید. 

2- از محیط مجازی استفاده کنید. 

هنگام توسعه ی هر پروژه ی پایتون، همیشه توصیه می شود از یک محیط مجازی (Virtual Environment) استفاده کنید زیرا به جلوگیری از تضاد در ماژول های پایتون کمک می کند و همچنین ماژول های یکسانی در محیط های local و production داشته باشید. 

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

محیط های مجازی، توسعه، package کردن و ارسال برنامه های کاربردی امن پایتون را آسان تر می کند. اگر پکیج های مخربی در برنامه ی پایتون خود دارید، استفاده از یک محیط مجازی، از داشتن وابستگی های (dependencies) مخرب پایتون در پروژه ها و ارسال آن به محصول نهایی جلوگیری می‌کند. 

برای ایجاد یک محیط مجازی می توانید از Virtualenv یا Pipenv استفاده کنید که به ایجاد محیط های مجازی ایزوله کمک می کند.

با Pipenv می‌توانید نصب ها و محیط های مجازی خود را مدیریت کنید، درخت وابستگی خود را بررسی کنید و وابستگی های خود را برای آسیب پذیری های شناخته شده، اسکن کنید. 

همچنین می توانید Virtualenv را با استفاده از دستورات زیر راه اندازی کنید: 

pip install virtualenv
virtualenv -p /path/to/python <env_name>

3- پکیج ها را به روش صحیح import کنید. 

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

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

دو نوع Import نسبی وجود دارد: ضمنی و صریح (implicit and explicit). 

Implicit imports مسیر منبع را نسبت به ماژول فعلی مشخص نمی کند در حالی که Explicit imports مسیر دقیق ماژولی را که می خواهید وارد کنید نسبت به ماژول فعلی مشخص می کند.

Import های ضمنی مورد تایید نبودند و از Python 3 حذف شده اند، زیرا اگر ماژول مشخص شده ای در مسیر سیستم پیدا شود، می تواند import شود و این بسیار خطرناک است. 

از آن جایی که ممکن است یک ماژول مخرب با همین نام در یک کتابخانه منبع باز (Open Source) محبوب وجود داشته باشد و راه خود را به مسیر سیستم پیدا کند، اگر ماژول مخرب قبل از ماژول واقعی پیدا شود، import شده و می تواند برای سو استفاده از برنامه هایی که آن را در درخت وابستگی خود دارند، استفاده شود.

برای جلوگیری از این امر، مطمئن شوید که از import های مطلق یا import های نسبی صریح استفاده می‌کنید، زیرا تضمین می‌کند که ماژول واقعی و مورد نظر را import کنید.

from safe_module import package, function, class

یا 

from  ..relative_module import package, function, class

اگر هنوز از Python 2 استفاده می کنید، مطمئن شوید که استفاده از import های نسبی ضمنی را حذف کرده اید، همان طور که در  Python 3 حذف شده است. 

4- مراقب فرمت رشته ها باشید. 

با این که پایتون معتقد است یک راه برای انجام کار ها دارد، اما چهار روش مختلف برای فرمت رشته ها دارد (سه روش برای نسخه های قبل از Python 3.6).

فرمت رشته به تدریج انعطاف پذیر و قدرتمندتر شده است، اما با افزایش انعطاف پذیری، پتانسیل برای اکسپلویت ها نیز افزایش می یابد. به همین دلیل، کاربران پایتون باید دقت داشته باشند که چگونه رشته ها را با ورودی های ارائه شده توسط کاربر فرمت می کنند. پایتون یک ماژول داخلی به نام string دارد. این ماژول شامل کلاس Template است که برای ایجاد رشته های template استفاده می شود.

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

نسخه ی Python 3، دستور های 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 = “Toby”

email = “oyetoketoby80@gmail.com”

user = User(name, email)

print(f”{user.__init__.__globals__[‘CONFIG’][‘API_KEY’]}”)

/* secret_key */

با این کار، داده های حساس global از dictionary به نام CONFIG، از طریق آرگومان قابل دسترسی هستند. 

با این حال، پایتون یک ماژول string داخلی دارد که می تواند برای رفع و جلوگیری از این مورد استفاده شود. با استفاده از کلاس Template از ماژول string: 

from string import Template
name_template = Template("Hello, my name is $name.")
greeting = name_template.substitute(name="Tobi")


/* Hello, my name is Toby */

این ماژول string برای مدیریت ورودی های کاربر و داده های تولید شده، خوب است.

5- درخواست های HTTP پایتون را ایمن مدیریت کنید. 

هنگام استفاده از کتابخانه ی درخواست های HTTP مانند Requests، نباید نسخه هایی را که ممکن است نسخه قدیمی و آسیب پذیر این ماژول را نصب کنند، در applications.txt خود پین (pin) کنید. یعنی آخرین نسخه را نصب کنید چون ممکن است نسخه های قدیمی تر، آسیب پذیر باشند.  

به عنوان مثال، Requests از Certifi برای مدیریت تایید SSL استفاده می کند، مطمئن شوید که آن را به یک سایت غیر بهره برداری شده (non-exploited)  ارسال می کنید. به طور پیش فرض، Requests تایید گواهی SSL را کنترل می کند و در صورت اعتماد به منبع، می تواند غیرفعال شود. 

url = “http://trusted_url”
requests.get(url, safe=False)

این کار تضمین می‌کند که درخواست هایی را به منبع مخرب (exploited) ارسال نمی کنید که می تواند کدهای مخرب را در هدرها یا بدنه ی Response ارسال کند. 

بنابراین برای جلوگیری از این امر مطمئن شوید که از آخرین نسخه کتابخانه یHTTP requests  استفاده می‌کنید. در صورتی که کتابخانه ی تایید SSL، منبعی را که درخواست ها را به آن ارسال کرده‌اید، مدیریت می‌کند، آن را تایید کنید. همچنین اگر از کتابخانه ی استاندارد urllib استفاده می‌کنید، باید بهترین روش ها را برای جلوگیری از درخواست های نامعتبر، دنبال کنید.

6- هنگام دانلود پکیج ها مراقب باشید. 

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

اکثر پکیج های پایتون در PyPI (Python Pack Index) منتشر می‌شوند و یک مخزن کد برای پکیج های پایتون است و هیچ گونه بررسی یا بررسی امنیتی را انجام نمی‌دهد. این بدان معناست که هر کسی که فکر مخربی دارد می‌تواند به راحتی پکیجی را با کد مخرب در PyPI بسازد و منتشر کند یا گاهی پکیجی را با نامی مشابه با یک پکیج محبوب منتشر کند و ویژگی‌های پکیج را تقلید کند. البته اگر شخصی یک پکیج مخرب یا مشکلی را در PyPI گزارش کند، به آن رسیدگی می شود، اما پکیج های اضافه شده به PyPI تحت بررسی قرار نمی گیرند.

هر پکیج پایتونی را که نصب و import می‌کنید، با دقت آن را بررسی کرده تا از نداشتن اکسپلویت مطمئن شوید یعنی از پکیج هایی که قبلا اکسپلویت شده اند، در کد خود جلوگیری کنید. همچنین، می‌توانید از ابزارهای امنیتی برای اسکن وابستگی های پایتون خود، برای غربال کردن پکیج های مخرب، استفاده کنید. 

به خاطر داشته باشید که بسته هایی که می توانند از طریق Python Packaging Index (PyPI) نصب شوند، همیشه برای بدافزار اسکن نمی شوند. این مسئولیت شماست که قبل از استفاده به طور کامل بررسی کنید که آیا هر چیزی که نصب کرده اید واقعاً ایمن است.

7- همیشه داده های خارجی را ضد عفونی (Sanitize) کنید. 

یکی از راه های حمله برای هر برنامه، داده های خارجی است که می تواند برای حملات SQL Injection، XSS یا منع سرویس (DOS) استفاده شود. یک قانون کلی برای حفظ امنیت پایتون این است که همیشه داده هایی که از منابع خارجی می آید، پاک سازی کنید (حذف اطلاعات حساس) چه از یک فرم ورودی کاربر، چه از یک وب سایت یا درخواست پایگاه داده سرچشمه گرفته باشد. همچنین، به محض ورود داده ها به برنامه، آن ها را اعتبارسنجی کنید تا از جا به جایی نا امن جلوگیری شود. 

8- مجوزهای وابستگی ها را مرور کنید. 

هنگام استفاده از یک پروژه ی منبع باز، مهم است که بدانید این پروژه ها چگونه مجوز می گیرند. پروژه های منبع باز، رایگان و قابل استفاده هستند، اما ممکن است هنوز شرایط و ضوابطی اعمال شود. این شرایط به طور معمول شامل نحوه ی استفاده از نرم‌افزار، این که آیا نیاز به ایجاد هرگونه تغییری در نرم افزار در دسترس عموم دارید، و سایر الزامات مشابه است. شما باید با مجوزهای منبع باز لازم برای پروژه هایی که استفاده می کنید آشنا شوید، بنابراین مطمئن باشید که از نظر قانونی خود را به خطر نمی اندازید.

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

9- DEBUG = False را در محصول نهایی تنظیم کنید. 

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

به طور پیش فرض، بیشتر فریم ورک ها اشکال زدایی را روشن می‌کنند. برای جلوگیری از نشت اطلاعات حساس برنامه، مطمئن شوید که اشکال زدایی را به False تغییر داده اید.  

10- (خیلی با احتیاط) سریال سازی De)serialize)کنید.

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

پایتون یک مکانیزم داخلی برای serialize و deserialize اشیا پایتون به نام pickling فراهم می‌کند. این مکانیزم ناامن شناخته شده است و توصیه می شود از آن با احتیاط و فقط در منابع داده قابل اعتماد استفاده شود.

یکی از بهترین پکیج ها برای انجام این کار PyCrypto است زیرا داده های شما را به طور ایمن deserialize می‌کند و از اجرای کد دلخواه جلوگیری می‌کند.

YAML نوع دیگری از انواع داده است که بیشتر برای پیکربندی داده ها استفاده می شود و با استفاده از پکیج PyYAML مدیریت می شود. پکیج PyYAML مکانیزمی را برای serialize انواع داده‌های سفارشی به YAML و بازگشت دوباره فراهم می‌کند. اما PyYAML، پر از بردارهای حمله ی احتمالی مختلف است. یک راه ساده اما موثر برای ایمن سازی استفاده از PyYAML، استفاده از ()yaml.SafeLoader به جای ()yaml.Loader به عنوان یک loader است. 

Data = yaml.load(input_file, Loader=yaml.SafeLoader)

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

اگر یک شی YAML با کد مخرب دارید، استفاده از تابع yaml.load کمکی نمی کند اما به شما امکان می دهد در صورت یافتن، کد مخرب را اجرا کنید. می توان با استفاده از yaml.safe_load برای جلوگیری از اجرای کدهای مخرب در هنگام جدا سازی داده های YAML در پایتون از این امر جلوگیری کرد. 

یکی دیگر از موارد استفاده معمولی XML است. کتابخانه های استانداردی وجود دارد که اغلب مورد استفاده قرار می گیرند، اما در برابر حملات معمولی آسیب پذیر هستند (یعنی حملات DOS). در برابر این مسائل امنیتی معمولی، XML دارای تدابیر امنیتی است. 

11- از عملکردهای خطرناک اجتناب کنید. 

معمولا می توانید با اجرا نکردن ورودی کاربر به عنوان دستور یا اسکریپت، از خطر تزریق کد (code injections) جلوگیری کنید. دو نوع عملکرد اصلی وجود دارد که منجر به آسیب پذیری های خطرناک از این نوع می شود:

  • Code injector ها، ورودی کاربر را می گیرند و آن را به عنوان کد تفسیر می کنند.
  • Command injector ها برای اجرای برنامه های کاربردی از خط فرمان، از داخل یک برنامه استفاده می شود.

قابل توجه ترین توابع در Code injector ها، ()eval  و ()exec هستند و ماژول subprocess در دسته Command injector ها است. 

12- برای جلوگیری از آسیب پذیری پکیج های منبع باز، آن ها را به روز نگه دارید. 

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

با این حال، گاهی اوقات این احتمال وجود دارد که یک حفره ی امنیتی ظاهر شود که می تواند بسیار خطرناک باشد. به همین دلیل، آسیب پذیری های منبع باز همیشه به محض کشف، منتشر می‌شوند و معمولا یک روش رفع و پیشگیری در نسخه ی بعدی منتشر می‌شود. هر چه زودتر آخرین به روز رسانی بسته منبع باز را داشته باشید، امنیت بهتری خواهید داشت. 

 در پایان این نکته را نیز در نظر داشته باشید که می توانید کدتان را اسکن کنید. توسعه دهندگان طیف گسترده ای از ابزارهای تحلیل کد استاتیک را برای حفظ امنیت پایتون در اختیار دارند. کدتان را با استفاده از این ابزار ها، اسکن کنید. برخی از این ابزار ها که هر کدام، کار خاصی را بررسی می کنند، عبارت اند از: 

  • pep8
  • pylint
  • flake8
  • bandit
  • Snyk Code

جمع بندی 

کدنویسی امن در پایتون در واقع تا زمانی که قوانین و اقدامات اولیه را رعایت کنید بسیار آسان است. بسیاری از توسعه دهندگان این موضوع را در نظر نمی‌گیرند، زیرا تنها به انجام وظایفی می پردازند که از برنامه ی در حال توسعه، انتظار می رود. همیشه توصیه می‌شود هنگام نوشتن پروژه های پایتون، این موارد امنیتی را در ذهن داشته باشید و آن ها را به کار بگیرید. 

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

شنیدن این اپیزود از رادیوفول‌استک را به شما پیشنهاد می‌دهیم

از بهترین نوشته‌های کاربران سکان آکادمی در سکان پلاس