هنگام ایجاد یک سایت، در لیست اولویت های شما امنیت آن باید جایگاه بالایی داشته باشد. امروزه بسیاری از افراد از ابزارهای رایگان، کلمات عبور ضعیف و کدهای ناامن استفاده می کنند. همه این موارد به راحتی می تواند سایت شما را در معرض خطر قرار دهد و بدین ترتیب تمام اطلاعات شما نیز در معرض نفوذ قرار می گیرند یا حتی از بین می روند. در این مقاله سعی خواهیم کرد تا نکاتی را درباره حملات SQL injection (تزریق اسکیوال) و نحوه مقابله با این نوع حملات بیان کنیم.
SQL Injection (تزریق در پایگاه داده یا دیتابیس) یک روش برای قرار دادن کد مخرب به یک فرم وب به عنوان بخشی از پرس و جو SQL است، به نحوی که برنامه را متقاعد کند کد جدید وارد شده SQL را به جای کد اصلی SQL اجرا کند. هنگامی که SQL injection موفقیت آمیز باشد، پایگاه داده و داده های آن در معرض خطر هستند. SQL injection به فرد مزاحم اجازه خواندن، به روز رسانی، تغییر و حتی حذف داده های پایگاه داده را می دهد. این شامل اطلاعات حساسی مانند رمزهای عبور و اطلاعات کارت های اعتباری است که معمولا انگیزه اصلی برای این نوع حملات می باشد.
راه های محافظت از سایت شما از چنین نفوذی، پیچیده نیست. با توجه به اینکه بیش از ۲۰٪ از آسیب پذیری های وب مربوط به SQL injection است، برای توسعه دهندگان درگیر با SQL ضروری است مطمئن شوند که حداقل اقدامات اساسی برای جلوگیری از این نوع آسیب پذیری ها، در دیتابیس آنها صورت گرفته است.
چگونه از پایگاه داده خود در مقابل حملات SQL injection محافظت کنیم:
عدم اعتماد به کاربران
هرجا که ورودی کاربر وجود داشته باشد، باید اطمینان حاصل کنید که پایگاه داده خود را همیشه محافظت می کنید. اگر برای مثال فرمی مخصوص وارد کردن یک عدد توسط کاربر دارید (به عنوان مثال یک فیلد شماره تلفن)، مطمئن شوید که در فرم وب موجود در برنامه خود تعریف کرده اید که فقط اعداد به عنوان مقدار معتبر برای آن فیلد پذیرفته می شوند و بدین ترتیب پایگاه داده خود را ایمن کنید. برای درک اینکه چرا اعتبارسنجی ورودی کاربر برای جلوگیری از حملات SQL injection ضروری است، بیایید با یک سناریوی دنیای واقعی امتحان کنیم:
فرض کنید که یک مهاجم تصمیم به آزمایش فرم ورود برنامه شما برای آسیب پذیری ها را دارد. در سورس کد برنامه شما، پرس و جوی SQL که بررسی می کند که یک کاربر معین در پایگاه داده شما وجود دارد، ممکن است شبیه کد زیر باشد:
SELECT * FROM users WHERE email = ‘<user_input_from_the_login_form>’;
اگر مهاجم آن را به صورت ۱′ OR ‘۱’ = ‘۱ پر کند و شما در فیلد نام کاربری هیچ گونه اعتبارسنجی ورودی انجام ندهید، query نهایی که اجرا خواهد شد مانند SELECT * FROM users WHERE email = ‘۱’ or ‘۱’ = ‘۱’ خواهد بود.
مهاجم به سادگی یک شرایط اضافی برای پرس و جو ارائه می دهد که همیشه درست باشد (۱ = ۱) و نتیجه آن این است که احتمالا کل محتوای پایگاه داده های کاربران شما را دریافت می کند که می تواند شامل ایمیل، نام کاربری، رمز عبور و … باشد. شما می توانید چند اقدام ساده برای جلوگیری از این نوع حمله انجام دهید:
-
فرار از quotes در ورودی های متنی
همانطور که در مثال بالا مشاهده کردید، نقل قول ها معانی خاصی در Query های SQL دارند، بنابراین لازم است از تمام نقل قول ها در فیلد های ورودی کاربر فرار کنیم. اکثر زبان های برنامه نویسی، توابع ساختگی را برای فرار از ورودی متن قبل از قرار دادن آن در پایگاه داده (مثلا فانکشن () mysql_real_escape_string در PHP) فراهم می کنند. Escaped quotes در مثال فوق معنای خاصی ندارند و query به درستی اجرا می شود.
-
محدود کردن تعداد ردیف های بازگشتی هنگام تایید اعتبار نام کاربری و رمز عبور
زمانی که بررسی می کنید که آیا کاربر در پایگاه داده شما موجود است یا خیر، فقط یک ردیف از جدول نیاز دارد، نه همه ردیف های جدول. با استفاده از عبارت MySQL LIMIT یا Microsoft SQL TOP اطمینان حاصل کنید که حتی اگر مانند مثال قبلی، یک مهاجم به طور موفقیت آمیز SQL injection را اجرا کرد، تنها جزئیات یک کاربر را دریافت کند:
SELECT * FROM users WHERE email = ‘<user input>’ LIMIT ۱; SELECT TOP ۱ * FROM users WHEREemail = ‘<user input>’;
-
انتخاب فقط یک فیلد از جدول هنگام چک کردن وجود یا عدم وجود داده ها
تحت هیچ شرایطی از * (تمام فیلد ها) استفاده نکنید. برای مثال، اگر فقط بررسی می کنید که آیا آدرس ایمیلی که توسط کاربر وارد شده در حال حاضر وجود دارد، فقط شناسه کاربر را انتخاب کنید. بدین ترتیب در صورتی که حملات SQL injection، به پایگاه داده شما نفوذ کند، تنها شناسه کاربر در معرض خطر قرار می گیرد، نه همه اطلاعات کاربر:
SELECT userid FROM users WHERE email = ‘<user input>’ LIMIT 1;
-
ارائه حداقل دسترسی به پایگاه داده
به دنبال قاعده اصلی که “هرگز به کاربر اعتماد نکنید”، یک اقدام دیگر برای حفاظت از حساب کاربری شما این است که دسترسی کاربران به پایگاه داده را با حداقل سطح دسترسی مورد نیاز فراهم کنید. اگر کاربر فقط به دسترسی “select” نیاز دارد، آن را مجاز به delete و یا drop کردن جداول نکنید. همچنین اگر از برنامه های مختلف استفاده می کنید، فراموش نکنید دسترسی به پایگاه های داده خود را جدا کنید، به این معنی که اگر یک کاربر نیاز به دسترسی به یک برنامه خاص را داشته باشد، فقط دسترسی آن برنامه به کاربر اعطا شود و به دیگر برنامه ها دسترسی نداشته باشد.
پیاده سازی mod_security
این قابلیت یک حفاظت دیگر است که امنیت پایگاه داده های شما را افزایش می دهد. mod_security یک فایروال مبتنی بر برنامه است که در برابر طیف وسیعی از حملات وب سایت شما را محافظت می کند.
استفاده از stored procedures
این موضوع عمدتا هنگامی مفید است که برای یک پایگاه داده تعیین شده که به صورت اشتراکی استفاده شود. اگر شما تعداد زیادی کاربر با دسترسی به پایگاه داده داشته باشید، باید اطمینان حاصل کنید که داده ها ابتدا مورد تایید قرار می گیرند. از آنجا که نباید هیچ وقت به کاربران اعتماد کنید و با توجه به اینکه نمی دانید آنها چه نوع اعتبارسنجی ایجاد کرده اند و آن چقدر امن است، شما باید اطمینان حاصل کنید که اعتبارسنجی را خودتان ایجاد کرده اید. در نتیجه حتما باید stored procedure های سفارشی (توابع، به طور مستقیم در پایگاه داده ذخیره شده) را برای تمام عملیات که کاربران انجام می دهند مانند select، insert و غیره ایجاد کنید. stored procedure ها قبل از انجام، عملیات درخواستی کاربر آن را اعتبارسنجی می کنند. سپس شما فقط این توابع را به کاربران نمایش می دهید و آنها در صورتی که دستورات واقعی SQL را به کار ببرند، می توانند از آنها استفاده کنند. این عمل در واقع یک لایه انتزاعی ایجاد می کند که در این مورد می تواند به عنوان سپر محافظ دیگری برای پایگاه داده شما عمل کند، زیرا کاربران به طور مستقیم با آن ارتباط برقرار نمی کنند.
استفاده از statements های آماده شده و کوئری های پارامتریک
هنگامی که از statements های آماده شده به جای ایجاد پرس و جو SQL به صورت پویا استفاده می کنید، ابتدا یک الگو از کل query ایجاد کنید، همه پارامترهایی که شامل اطلاعات ورودی کاربر هستند را با یک پارامتر (به عنوان مثال علامت سوال) نمایش دهید. سپس، زمانی که statements های آماده شده اجرا می شود، تمام پارامترها با ورودی کاربر واقعی جایگزین می شوند، داده ها اعتبارسنجی می شوند و پس از آن تنها کوئری های واقعی اجرا می شوند. بیشتر زبان های برنامه نویسی محبوب مانند جاوا، C# ،Perl ،PHP و … یا به صورت داخلی statements های آماده شده را پشتیبانی می کنند و یا با ارائه کتابخانه های خارجی به شما این امکان را می دهد، که از آن ها در برنامه خود استفاده کنید.
Salted hashes
مهاجم زمانی که بتواند یک نقطه ضعف در امنیت شما پیدا کند، به آن نفوذ خواهد کرد. چیزی که برای تضمین امنیت کاربران خود می توانید انجام دهید، استفاده از به اصطلاح ‘slated hashes’ برای کلمات عبور آنهاست. چیزی که این قابلیت انجام می دهد اضافه کردن کاراکترهای تصادفی (‘salt’) به رمز عبور است و سپس این رشته به اصطلاح hash می شود. با توجه به این که اکثر افراد از رمز عبور مشابه برای حساب های مختلف در سایت های متفاوت استفاده می کنند، در صورتی که اطلاعات شما در معرض خطر قرار گرفته باشد، حداقل مهاجم می تواند تنها از کلمه عبور برای سایت خود استفاده کند و تمام حساب های دیگر کاربران به خطر نمی افتد.
اگر تمام مراحل ذکر شده در بالا را دنبال کنید، اطمینان حاصل خواهید کرد که پایگاه داده های شما نسبت به حملات SQL injection بسیار امن تر است. با توجه به میزان زیاد حملات brute force بر اساس این روش، برنامه شما ۲۰٪ امنیت اضافی به دست آورده است.