در این پست آموزشی به زبان ساده در مورد SQL injection  صحبت میکنم. مفهومی که شما به عنوان طراح سایت حتما باید بلد باشید و راههای مقابله با اون رو بدونید.

SQL Injection چیست؟

قبل از اینکه بحث رو شروع کنم بد نیست این تذکر رو بدم که همه مثالهای این پست با SQL  و PHP مطرح شده ولی اگر شما آشنایی با این زبان ندارید جای نگرانی نیست چون مثالها ساده است و هدف من در این آموزش انتقال مفهوم SQL Injection به شماست.

خب بریم سراغ بحثمون. با یک مثال شروع میکنم. شما فرض کنید که همیچ کدی سمت سرور نوشتید:

SELECT * 
FROM users
WHERE username='$username' AND password = '$password' 

در کد بالا قراره اطلاعات یک کاربر خاص رو از جدول users بیرون بکشیم. اما چه کاربری؟ کاربری که نام کاربری و پسوردش در متغیرهای username و password ذخیره شده. این اطلاعات از کجا میاد؟ طبیعتا از سایت یا اپلیکیشنی که طراحی کردیم. دقیق تر بخوام بگم کاربر اطلاعات کاربریش رو در سایت وارد میکنه و این اطلاعات از طریق دو متغیری که اسم بردیم وارد کدهای SQL  میشه. واینجاست که ما داریم خطر رو به جون میخریم! چرا؟ چون کاربر هر چیزی که تو سایت به عنوان یوزر نیم و پسور وارد کنه عینا وارد کدهای SQL  ما میشه. حالا اگه کاربر (که دیگه باید بهش بگیم هکر) یوزرنیمش رو اینجوری وارد کنه فاجعه به بار میاد:

Hamid'; DROP DATABASE xyz –

هکر با وارد کردن یوزرنیم بالا میتونه دیتابیسِ سایت شما رو پاک کنه (البته باید اسم دیتابیس رو درست وارد کنه) چرا؟ بیایم یوزرنیم رو جایگذاری کنیم در کد:

SELECT * 
FROM users
WHERE username='Hamid'; DROP DATABASE  xyz –  AND password = '123' 

فکر کنم دیگه همه چیز روشنه! هکر با دستوراتی که وارد کرد به دستور select  خاتمه میده ، دیتابیس رو پاک میکنه و با — (دو تا خط فاصله) همه دستورات بعدی رو کامنت میکنه.

با همین ایده هکر میتونه کارهای دیگه ای هم کنه، مثلا چی؟
حذف یک جدول خاص، دسترسی به اطلاعات همه کاربران و تغییر رمز عبور ادمین سایت. برای مواردی که گفتم هم کافیه هکر یه چیزی شبیه به این رو وارد کنه:

حذف یک جدول خاص:

Hamid'; DROP TABLE xyz –

SELECT * 
FROM users
WHERE username='Hamid'; DROP TABLE xyz –  AND password = '123' 

دسترسی به اطلاعات همه کاربران:

Hamid' OR 1=1 --

SELECT * 
FROM users
WHERE username='Hamid' OR 1=1  -- AND password = '123' 

تغییر رمز عبور ادمین سایت

Hamid'; update users set password='hackShodiRaft' where user='administrator'--

SELECT * 
FROM users
WHERE username='Hamid"; update users set password='hackShodiRaft' where user='administrator' -- AND password = '123' 

البته باید تکرار کنم که اسم دیتابیس، جدول یا هر چیز دیگه ای که تو مثالها میبینید رو هکر یا باید حدس بزنه یا به طریقی باید به دستشون بیاره. اما اینو باید در نظر داشته باشیم که برنامه نویسی که به فکر جلوگیری از حمله های این شکلی به سایتش نیست احتمال داره از اسامی شناخته شده ای برای دیتابیس و جدولش استفاده کنه و اینجوری کار هکر رو راحت تر کنه

چگونه از SQL Injection در امان باشیم؟

اگر تا اینجای بحث رو متوجه شده باشید احتمالا این سوال به ذهنتون میرسه: من فهمیدم SQL Injection چیه، حالا چه جوری باید امنیت سایتم رو بالا ببرم که هکر ها از این روش نتونن به سایت ما نفوذ کنن؟
برای مقابله با SQL Injection چندین روش ساده ولی در عین حال قدرتمند وجود داره که من 4 تاش رو بررسی میکنم:
1- input validation

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

مثلا شما فرض کنید در سایتتون یک قسمت دارید که کاربر میتونه به پست شما امتیاز بده (امتیاز 1 تا 5) پس طبیعیه که هر چیزی غیر از اعداد 1 تا 5 دریافت میشه یعنی هکر تو این داده ها نقش داره. پس کافیه یک اعتبارسنجی روی متغیر امتیاز داشته باشیم:
<?php
if(isset($_POST["selRating"]))
{
    $number = $_POST["selRating"];
    if((is_numeric($number)) && ($number > 0) && ($number < 6))
    {
        echo "Selected rating: " . $number;
    }
    else
        echo "The rating has to be a number between 1 and 5!";
} 
2- Escaping

در مثالهایی که برای هک شدن سایت زدم دیدید که کوتیشن نقش اساسی رو بازی میکرد. یعنی با استفاده از کوتیشن و سیمی‌کالون بود که دستور select تموم شد و دستور دلخواه هکر وارد کدهای sql شده بود. بنابراین یکی از روشهای مقابله با sql injection میتونه این باشه که کاراکترهایی که میتونند منجر به یک دستور ناخواسته در sql بشند رو حذف کنیم. در php این کار رو تابع mysqli_real_escape_string انجام میده:

$username = mysqli_real_escape_string($db_connection, $_POST['username']);
$password = mysqli_real_escape_string($db_connection, $_POST['password']); 
3- Parametrized queries

از نظر من کاراترین روشی که میشه به کار برد همین روشه. در این روش یه جورایی مسولیت کنترل کدهای خطرناک رو میندازیم رو دوش php! چه جوری؟ کافیه متغیرهایی که از سایت دریافت میکنیم رو به php معرفی کنیم. یعنی کوئریمون رو جوری بنویسیم که اصطلاحا متغیرها به کوئری bind بشن. اینجوری مطمئن خواهیم بود که اگه دستورات خطرناکی از سمت هکر دریافت بشه در کوئری اجرا شده بی اثر خواهد شد.

$sql = "SELECT username 
            FROM users
            WHERE id = :id";
$query = $db_connection->prepare($sql);
$query->bindParam(':id', $id); 

در کوئری بالا نوشته شده id=:id و پایینتر عمل bind شدن (مقید کردن) انجام میشه و اونجا به php میگیم منظور ما از :id در کوئری متغیر $id است که دریافت کردیم. پس حواست باشه که دستورات خطرناکی داخلش نباشه!

4- stored procedures

من اینجا قصد آموزش stored procedures رو ندارم ولی اگه ساده بخوام بگم پروسیجرها در واقع توابعی هستند که در دیتابیس ذخیره میشن و یه میشه گفت سمت سرور اجرا میشن. دستورات و نحوه فراخوانی پروسیجر به صورتیه که شبیه به کوئریهای پارامتر شده است توضیح دادم و به این شکل میشه جلوی sql injection رو بگیریم

با روشهایی که گفتیم آیا سایت ما 100 درصد امن میشه؟

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

ولی با مواردیکه گفتم اگر در سایتتون لحاظ کنید میتونم بگه که حداقل جوجه هکرها نمیتونند به سایت شما آسیب برسونن 😉