علیرضا آهنی
علیرضا آهنی
خواندن ۲ دقیقه·۴ سال پیش

چرا استفاده از توابع eval ، system و ... در برنامه نویسی کار نادرستی است

قبل از آشنایی با دلیل اشتباه بودن این کار باید با کار این توابع آشنا بشیم. در این مطلب از پایتون و C++ استفاده میشه اما این موارد تقریبا در بیشتر زبان های برنامه نویسی درسته.



تابع eval در پایتون

این تابع کد پایتون ورودی را اجرا میکنه و خروجی آن را به خروجی تابع میده. مثال:

>>> eval('print(&quotrunning in eval&quot)') running in eval >>> eval(&quot10+20&quot) 30

یکی از استفاده های بسیار زیاد از این تابع در ماشین حساب ها هست. زیرا همینطور که در بالا می‌بینید این تابع خروجی عددی عبارت های ریاضی رو به خروجی میده. مثال:


>>> print(f&quotans:{eval(input(':'))}&quot) :10**20 ans:100000000000000000000


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

>>> password = &quotsecret password&quot >>> print(f&quotans:{eval(input())}&quot) password ans:secret password


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

برای همین استفاده از تابع eval کار درستی نیست.



تابع system

این تابع کامند یا فایل ورودی رو در shell سیستم عامل اجرا میکنه. برای دیدن محل فایل یک کامند میتونید از برنامه which یا whereis در ترمینال استفاده کنید:

alireza@fedora ~> which cat /usr/bin/cat

این برنامه ( و بیشتر برنامه ها ) از ENV variable استفاده میکنن تا بدونن توی کجا باید دنبال برنامه باشن. ENV variables مقدار هایی هستن که سیستم عامل به هربرنامه ای که اجرا میشه ارسال میکنه. یکی از این مقادیر PATH نام داره. هر برنامه ای که بخواد کامندی رو اجرا کنه داخل دایرکتوری های متغییر PATH جست‌وجو میکنه و اگر پیدا نشد دیگه ادامه نمیده.

متغییر PATH رو میشه به شکل زیر از ترمینال مشاهده کرد:

alireza@fedora ~> echo $PATH /usr/local/bin /usr/local/sbin /usr/bin /usr/sbin

حالا چرا از تابع system استفاده نکنیم؟

برنامه زیر رو در نظر بگیرید:


#include <iostream> int main() { system(&quotdate&quot); }

که با دستور زیر کامپایل شده:

g++ main.cpp -o main

برنامه کامپایل شده این خروجی میده:

Sun May 16 12:03:40 PM +0430 2021

حالا فرض کنید میخواید یک دستور دیگه بجز date اجرا کنید ( مثلا یک دستور مخرب ) اما دسترسی به ویرایش خود باینری برنامه ندارید.

چطور میشه این مسئله رو حل کرد؟

یک برنامه جدید به اسم date کامپایل میکنیم:

#include <iostream> int main() { std::cout << &quotMy evil program!!&quot << std::endl; }

و متغییر PATH رو به محل برنامه تغییر میدیم و برنامه رو اجرا میکنیم:

> export PATH=. > echo $PATH . > ./main My evil program!!

و از این بدتر ، اگر برنامه رو فقط بتونیم بخونیم و برنامه برای کاربر root باشه ،‌ میتونیم دسترسی به shell کاربر root هم داشته باشیم!

برای همین استفاده از این دو تابع درست نیست و جزو توابع خطرناکه.


برنامه نویسیsystemrootامنیت
شاید از این پست‌ها خوشتان بیاید