اجرا کردن نرمافزارهای تحت وب ممکن است شبیه بازی کردن بازی رولت روسی باشد. با اینکه رسیدن به یک سطح امنیتی بالا روی وب در تئوری ممکن است، ولی در جهان واقعی همیشه یک نقطه ضعیف وجود دارد. تنها یک لغزش و خطا در کد کافی است تا حمله کنندگان را قادر سازد تا به اطلاعات شما دسترسی پیدا کنند. اگر شما یک نرمافزار تحت وب عمومی با کمی پیچیدگی در حال اجرا داشته باشید، این احتمال وجود دارد که نوعی اشکال امنیتی در آن وجود داشته باشد. برای مثال URL مثال زیر را ببینید:
http://www.webapp.com/login.php?user…ABLE%20users—
در صورتی که نرمافزار شما در مقابل SQL Injection ضعف داشته باشد، فراخوانی آدرس بالا ممکن است به راحتی کلیه اطلاعات کاربرانتان را پاک کند. آیا از اطلاعات بانک اطلاعاتی خود بطور مرتب نسخههای پشتیبان تهیه میکنید؟
mod_security یک سیستم کشف و پیشگیری از مزاحمت مخصوص برنامههای کاربردی وب است. به زبان دیگر میتوان آنرا دیوار آتش برنامههای کاربردی وب نیز نامید. این سیستم به صورت یک ماژول بر روی سرویسدهنده وب آپاچی نصب شده و همانند یک چتر حفاظتی بر روی برنامههای کاربردی وب عمل مینماید.
یک تصویر شماتیک از نحوه عمل ModSecurity
چرا باید از mod_security استفاده کنید؟ چند سال پیش که من (نگارنده) شروع به کار بر روی mod_security کردم، از snort برای مانیتور کردن ترافیک وب خود استفاده میکردم. من خیلی خوب کار کرده بودم. به Snort گفته بودم که چه کلمات کلیدی برای من جالب است و این برنامه هرگاه که به این کلمات کلیدی بر میخورد، به من اطلاع میداد. ولی من به چیز بیشتری نیاز داشتم. من مایل بودم بتوانم آزادی لازم برای تعریف قوانین پیچیده و توانایی اجرای عکس العملهای مرتبط با HTTP را داشته باشم. علاوه بر این، نصب و پیاده سازی یک سیستم کشف مزاحمت (IDS) هر جا که یک سرویسدهنده وب وجود داشته باشد کاری است بسیار وقت گیر و گران. در همان زمان سعی کردم تا از ترکیب mod_rewrite و mod_setenvif استفاده کنم. با استفاده از mod_rewrite تشخیص کلماتی مانند drop و table بسیار آسان بود و میتوانستم سرویس گیرنده ارسال کننده چنین کلماتی را به آدرس دیگری دور از نرمافزار وب هدایت کنم تا از حمله جلوگیری شود. البته این کار تنها جلوی نفوذگران کم تجربه را میگرفت. نفوذگران پرتجربهتر میتوانستند با بکارگیری متد POST بجای GET همان URL مورد نظرشان را فراخوانی کنند. از آنجایی که متغییرهای ارسال شده توسط متد پست توسط بسیاری از ماژولهای آپاچی در نظر گرفته نمیشوند، حمله میتوانست انجام شود. اکنون که نیاز به داشتن یک ابزار جدید برای پوشش دادن این نیاز حفاظتی ایجاد شده بود، من دو راه در مقابل خود داشتم: از جاوا استفاده کنم و یک سیستم Reverse ***** و Application Gateway برای نرمافزارهای تحت وب بنویسم، یا اینکه یک ماژول برای آپاچی بنویسم که در بالای کدهای موجود اجرا شود. راه نخست مستلزم صرف وقت بسیار بود و شاید از نتیجه کار نیز تعداد بسیار کمی استفاده میکردند (خودم هم از آن استفاده نمیکردم!) از آنجایی که مایل بودم ابزاری بنویسم که قابل انعطاف و سهل الاستفاده باشد، راه دوم را انتخاب کردم و هرگز پشت سر خود را نگاه نکردم. به مثالی که در بالا زدیم باز میگردیم. برای جلوگیری mod_security از حملهای که با drop table صورت میگیرد، کافی است خط زیر را به فایل پیکربندی سرویسدهنده آپاچی خود اضافه کنید: SecFilter “drop[[:space:]]table” تنها پارامتر SecFilter یک Regular Expression است که به درخواستهای وارد شده به سرویسدهنده اعمال میگردد. این شبیه کاری است که mod_rewrite انجام میدهد با این تفاوت که mod_security هم بر روی GET و هم بر روی POST عمل میکند. اینجا لازم است بگویم که پیاده سازی قابلیت مانیتور کردن POST بر روی آپاچی ۱٫۳ کار بسیار دشوار بود. نصب و پیکربندی یکی از بهترین راههای نصب mod_security کامپایل آن با استفاده از کد منبع است: $ /path/to/apache/bin/apxs -cia mod_security.c # apachectl stop # apachectl start برای اینکه قادر باشید تا ماژولهای آپاچی را با استفاده از apxs کامپایل و نصب کنید، باید بسته apache-dev را که به همراه توزیع شما موجود است، نصب کنید. مثلا در دبیان و توزیعهای مبتنی بر آن میتوانید از دستور زیر برای نصب apache-dev استفاده کنید: # apt-get install apache-dev در صورتی که بخواهید ماژول mod_security را بدون کامپایل نصب کنید، به احتمال قوی آن نیز به همراه توزیع مورد استفاده شما ارائه شده است. در دبیان میتوانید با دستور زیر آنرا نصب کنید: # apt-get install libapache-mod-security پس از نصب باید اطمینان حاصل کنید که ماژول آن در سرویسدهنده فعال باشد. کافی است بررسی کنید که خط زیر در فایل etc/apache/modules.conf/ وجود داشته باشد و در صورتی که نیست آنرا بصورت دستی اضافه کنید: LoadModule security_module /usr/lib/apache/1.3/mod_security.so پس از اتمام نصب باید تعدادی خط به فایل پیکربندی سرویسدهنده آپاچی اضافه کنید: <IfModule mod_security.c> # Turn the filtering engine On or Off SecFilterEngine On
# Make sure that URL encoding is valid SecFilterCheckURLEncoding On
# Unicode encoding check SecFilterCheckUnicodeEncoding Off
# Only allow bytes from this range SecFilterForceByteRange 0 255
# Only log suspicious requests SecAuditEngine RelevantOnly
# The name of the audit log file SecAuditLog logs/audit_log # Debug level set to a minimum SecFilterDebugLog logs/modsec_debug_log SecFilterDebugLevel 0
# Should mod_security inspect POST payloads SecFilterScanPOST On
# By default log and deny suspicious requests # with HTTP status 500 SecFilterDefaultAction “deny,log,status:500”
</IfModule> در خطوط بالا، من توضیحات را باقی گذاشتهام تا کاملا قابل درک باشد. تنظیمات بالا mod_security را فعال خواهد ساخت ولی با این تنظیمات کار زیادی برای شما انجام نمیدهد. همیشه بهترین راه شروع با یک تنظیم ساده و تکمیل کردن آن با دستورات اضافهتر است. خوب حالا این چه کار میکند؟ حتی با این تنظیم ساده نیز mod_security دو سود دارد. نخست اینکه تعدادی تکنیک ضد گریز زنی اجرا میکند و باعث میشود که ورودی رسیده به سرویسدهنده یک ورودی متعارف و استاندارد باشد. این در قدم بعدی که شروع به اضافه کردن قوانین *****ینگ میکنید، مفید خواهد بود. تصور کنید میخواهید جلوی اجرای دستور ps را با استفاده از یک Regular Expression مانند bin/ps ax/ بگیرید. این کار جلوی فراخوانی همین دستور را خواهد گرفت ولی در مقابل فراخوانیهایی مانند bin/ps%20ax/ یا bin//ps ax/ یا bin/ ./ps ax/ کاری انجام نخواهد داد. در زیر لیستی از کارهایی که mod_security در این مورد خواهد داد را میبینید: – حذف چند اسلش متوالی (//) – حذف فراخوانیهای دایرکتوری جاری (/.) – / و \ را بصورت یکسان تلقی میکند (فقط بر روی ویندوز) – عملیات URL Decoding را انجام میدهد – بایتهای خالی (۰۰%) و فضاهای خالی را حذف میکند دومین سود با فعال شدن تعدادی از بررسیهای توکار فراهم میشود: – بررسی صحت URL Encoding – بررسی صحت Unicode Encoding – بررسی صحت Byte Range که تنها مقادیر کاراکتری مشخصی میتوانند به عنوان بخشی از درخواست قرار گیرند عکس العملها هرگاه ورودی با یکی از قوانین تعریف شده مطابقت داشته باشد، تعدادی عکس العمل صورت خواهد گرفت. در بسیاری از مواقع، عکس العمل پیشگزیده که با SecDefaultAction تعریف میشود، مورد استفاده قرار میگیرد. این امکان وجود دارد تا برای هر قانون تعریف شده توسط SecFilter یک عکس العمل تعریف نمود. این کار با ارسال پارامتر دوم به این دستور یا پارامتر سوم به SecFilterSelective انجام میگیرد. عکس العملهای مورد پشتیبانی عبارتند از: – deny : که درخواست وارد شده را رد میکند. – allow : پردازش قوانین را متوقف کرده و به درخواست اجازه عبور میدهد. – status: nnn : با یک شماره وضعیت HTTP پاسخ میدهد. – redirect: url : درخواست را به صفحه دیگری هدایت میکند. – exec: cmd : یک دستور یا اسکریپت را اجرا میکند. – log : درخواست را در سیستم ثبت رخداد ثبت میکند. – nolog : درخواست را ثبت نخواهد کرد. – pass : از قانون فعلی عبور کرده و قانون بعدی را بررسی خواهد کرد. – pause: nnn : تقاضا را برای مقدار nnn میلی ثانیه متوقف میکند. باید در استفاده از این عکس العمل مراقبت کافی را داشته باشید. با هر توقف، یک پروسه آپاچی متوقف میشود و استفاده ناصحیح از این عکس العمل میتواند حمله کننده را قادر به ایجاد حملات DOS بر روی سرویسدهنده شما کند. عکس العملهای دیگری نیز وجود دارد که هماننده آنچه در mod_rewrite میبینیم، بر نحوه حرکت در میان قوانین موثر است: – chain: قانون بعدی موجود در زنجیره را بررسی میکند. هنگامی که عبور از یک قانون با شکست مواجه میشود، بقیه قوانین باقیمانده در زنجیره نیز نادیده گرفته میشوند. – skipnext: n: از قانون جاری به n قانون بعدی حرکت میکند. قوانین *****ینگ این قوانین به دو روش نوشته میشوند. در سادهترین روش: SecFilter keyword کلمه کلیدی مشخص شده بر روی خط نخست درخواستهای GET و یا محتویات درخواستهای POST در صورت وجود اعمال میگردد. این نحوه استفاده بسیار ساده بوده و شاید بیشتر برای مقالات آموزشی نظیر این مقاله مناسب باشد. در مقابل بهتر است قانون را به شکل زیر بکار بگیرید: SecFilterSelective “variable list separated with |” keyword استفاده از چنین قوانینی امکان تجزیه و تحلیل بهتر و مصرف کمتر زمان CPU را فراهم میکند. خوب، بجای ادامه دادن و خسته کردن شما با قوانین مختلف، اکنون به چند مثال جالب میپردازیم. این نمونه مثالها، مثالهایی هستند که بیشترین کاربردها را در جهان واقعی دارا میباشند. در مثال زیر، اجازه عبور تنها به یک شماره IP مشخص (مانند ایستگاه کاری من) داده خواهد شد. هیچ قانون دیگری پردازش نشده و از آنجایی که این قانون نماینده ایجاد حمله خاصی نیست، ثبت هم نمیشود: SecFilterSelective REMOTE_ADDR “^IP_ADDRESS_HERE$” nolog,allow در مثال زیر دسترسی کامل از کامپیوتر کیفیام هنگامی که در سفر هستم میدهد. بدلیل اینکه شماره IP من در این مورد نامشخص است، دسترسی با استفاده از وجود یک رشته به نام Blend 42 در فیلد User-Agent داده میشود. البته میزان حفاظت این گونه محدودیتهایی پایین است ولی میتواند در بالای مکانیسمهای دسترسی دیگر جالب باشد: SecFilterSelective HTTP_USER_AGENT “Blend 42” در مثال زیر، از ارسال کدهای SQL Injection با استفاده از کوکیها جلوگیری خواهد شد. در صورتی که کوکیی وجود داشته باشد، تنها اگر حاوی اعداد ۱ تا ۹ باشد اجازه عبور خواهد داشت. SecFilterSelective COOKIE_sessionid “!^(|[0-9]{1,9})$” در مثال زیر، وجود سرایندهای HTTP_USER_AGENT و HTTP_HOST بررسی میشود. معمولا حمله کنندههای بررسیهای خود را با استفاده از ابزارهای سادهای مانند telnet انجام میدهند و تمامی سرایندهای لازم را مانند آنچه مرورگرها انجام میدهند، ارسال نمیکنند. چنین درخواستهایی را میتوانید رد، ثبت یا مانیتور کنید. SecFilterSelective “HTTP_USER_AGENT|HTTP_HOST” “^$” در مثال زیر از هر گونه upload فایل از طریق مرورگرها جلوگیری به عمل خواهد آمد. این راهی ساده ولی موثر است. رد تقاضاها با استفاده از نوع محتویات مورد استفاده برای ارسال فایلها: SecFilterSelective “HTTP_CONTENT_TYPE” multipart/form-data قانون نمایش داده شده در مثال زیر، تمامی درخواستهای بدون سرایند Accept را برای بررسیهای آینده ثبت میکند. باز هم جلوی درخواستهای ارسالی دستی که حاوی تمامی سرایندها نیستند، میتواند گرفته شود. زیر نظر گرفتن سرایند Keep-Alive نیز گزینه خوب دیگری است. SecFilterSelective “HTTP_ACCEPT” “^$” log,pass قانون نمایش داده شده در مثال زیر، هنگامی که رئیسم یکبار دیگر کلمه عبور خود را فراموش کرده باشد، یک نامه الکترونیکی برای من ارسال میکند. در مثال زیر ما دو قانون داریم. نخستین قانون هنگامی اجرا میشود که یک فایل خاص فراخوانی شود. (در مثال ما فایلی که پیغام Login Failed را نمایش میدهد.) در قانون دوم هنگامی که کلمه عبور استفاده شده ceo باشد، اجرا میشود. همانطور که میبینید، یک اسکریپت خارجی را نیز اجرا میکند که این اسکریپت نامه را خواهد فرستاد. SecFilterSelective REQUEST_URI “login_failed\.php” chain SecFilterSelective ARG_username “^ceo$” log,exec:/home/apache/bin/notagain.pl مثال بعدی ربات Google را که میتوان آنرا با استفاده از فیلد User-Agent تشخیص داد، به آدرس دیگری هدایت کرده و اجرا شدن قانون را نیز ثبت نمیکند. SecFilter HTTP_USER_AGENT “Google” nolog,redirect:http://www.google.com مثال زیر، درخواستهای ورودی به سرویسدهنده را برای وجود جاوا اسکریپتها بررسی میکند آنهایی را که در متغییرهای با نام html قرار دارند، مورد پذیرش قرار میدهد. رد کردن تمامی درخواستهای حاوی تگهای جاوا اسکریپت میتواند مشکل ساز باشد. مخصوصا.هنگامی که بر روی سرویسدهنده شما نرمافزارهای مدیریت محتوا نصب شده باشد: SecFilter “ARGS|!ARG_html” “<[:space:]*script”در آخرین مثال، چگونگی داشتن چند تنظیم برای mod_security نمایش داده شده است. به اینصورت شما میتوانید تنظیمات خاصی را بر روی یک برنامه کاربردی نصب شده بر روی سرویسدهنده وب اعمال کنید. به چگونگی استفاده از دستور SecFilterInheritance توجه کنید. این دستور به mod_security میگوید که تمامی تنظیمات به ارث رسیده از بخش اصلی mod_security را در نظر نگرفته و با مقادیر تازهای شروع کند. <Location /anotherapp/> SecFilterForceByteRange 32 126 # Use this directive not to inherit rules from the parent context SecFilterInheritance Off
# Developers often have special variables, which they use # to turn the debugging mode on. These two rules will # allow the use of a variable “debug” but only coming from # the internal network SecFilterSelective REMOTE_ADDR “!^192.168.254.” chain SecFilterSelective ARG_debug “!^$” </Location> ملاحضات لازم برای سرعت من به شخصه هرگز مشکلی با سرعت در مورد mod_security نداشتهام. با آزمایشاتی که انجام دادهام، تفاوت سرعت چیزی در حدود ۱۰ درصد بوده است. البته در شرایط واقعی، افت سرعت کمتر است. بر روی سایتهای وب واقعی، یک درخواست ممکن است شامل درخواستهای زیادی برای اقلام استاتیک سایت مانند تصاویر، Stylesheet ها و مانند آن باشد. با استفاده از دستور زیر به mod_security خواهید گفت تا این اقلام را در نظر نداشته باشد: SecFilter DynamicOnlyبه طور عمده، گلوگاه mod_security در انجام عملیات خواندن/نوشتن روی دیسک است. باید دقت کنید که هرگر حالت Debug روی یک سرویسدهنده کاری فعال نباشد و حالت ثبت رخداد کامل را نیز در صورتی که واقعا به آن نیازی ندارید، فعال نکنید. در مثالهای نمایش داده شده در بالا، mod_security تنها برای ثبت رخدادهای خاصی تنظیم شده است. سایر قابلیتها الف) chroot داخلی در صورتی که سعی کرده باشید تا یک سرویسدهنده وب را در حالت chroot اجرا کنید، دیدهاید که برخی اوقات این یک کار دشوار است. با استفاده از mod_security این پیچیدگی به کناری خواهد رفت. با یک دستور میتوانید یک سرویسدهنده در حالت chroot داشته باشید: SecChrootPath /chroot/home/web/apache تنها نکته لازم این است که مسیر سرویسدهنده در chroot مشابه مسیر سرویسدهنده در خارج از chroot باشد. مثلا برای مثال بالا باید home/web/apache/ باشد. برای اینکه حتی فرایند chroot کردن آسانتر نیز باشد، شرایطی فراهم شده است که میتوانید یک chroot تنها حاوی اطلاعات داشته باشید. این از آنجایی امکانپذیر است که فراخوانی chroot به صورت داخلی انجام میگیرد. ب) تغییر امضای سرویسدهنده حمله کنندگان و اسکریپتهای خودکار بطور دائم اطلاعات مربوط به شماره نسخه سرویسدهنده شما را که در متغییر server موجود در سرایند HTTP ارسال میگردد، جمع آوری میکنند. برای تغییر این مقدار شما باید کد منبع آپاچی را تغییر دهید. با استفاده از دستور زیر به راحتی خواهید توانست تا نام سرویسدهنده خود را تغییر دهید. البته برای استفاده از این گزینه، در صورتی که از آپاچی سری ۱٫۳ استفاده میکنید، برای استفاده از این قابلیت باید mod_headers فعال باشد.