آشنایی با مفهوم SQL Injection در زبان PHP

آشنایی با مفهوم SQL Injection در زبان PHP

نیاز به توضیح نیست که SQL نام زبانی است که برای کار با سیستم مدیریت دیتابیسی همچون MySQL به کار گرفته می‌شود. واژهٔ Injection به معنی «تزریق» است و به طور کلی منظور از SQL Injection فرایندی است که از آن طریق هکرها دستوراتی از جنس SQL ایجاد کرده بنابراین به سادگی با استفاده از فرم‌های اینترنتی می‌توانند این دستورات را به سمت دیتابیس مد نظرشان ارسال نموده و به اهداف خود دست یابند که این اهداف می‌توانند شامل فراخوانی داده‌ها، حذف داده‌ها و دیگر اقداماتی از این دست باشند.

به نظر می‌رسد اگر اصطلاح «تزریق دستورات اس‌کیوال» را به عنوان معادلی برای SQL Injection انتخاب نماییم، معادل خیلی بدی انتخاب نکرده باشیم زیرا همان‌طور که از نام آن برمی‌آید، هکرها با تزریق کدهای مد نظر خود، به راحتی اقدام به نوشتن یکسری دستورات واقعی SQL می‌کنند و با استفاده از آنها به راحتی هر کاری که تمایل داشته باشند می‌توانند انجام دهند.

هکرها معمولاً برای SQL Injection، از فرم‌های اینترنتی مثل فرم تماس با ما، فرم ورود به ناحیهٔ کاربری، فرم ثبت‌نام و ... استفاده می‌کنند. برای روشن شدن این مسئله، فرم زیر را در نظر می‌گیریم:


<form action="script.php" method="post">
    <input type="text" name="username" placeholder="Please Enter Your Username">
    <input type="password" name="password" placeholder="Please Enter Your Password">
    <input type="submit" value="Login">
</form>

خروجی کدهای فوق به صورت زیر خواهد بود:

 آشنایی با مفهوم SQL Injection در زبان PHP

همان‌طور که در کد فوق می بینیم، فرمی داریم که حاوی ۲ فیلد است یکی برای نام کاربری و دیگری برای رمزعبور؛ اکشنی هم که برای این فرم در نظر گرفته‌ایم یک فایل PHP است تحت عنوان script.php حاوی کدهای زیر:


session_start();
$username_set = false;
$password_set = false;
$username = $_POST['username'];
$password = $_POST['password'];
if (empty($username)) {
    echo "<p class=\"error\">Please Enter your username</p>";
} else {
    $username_set = true;
}
if (empty($password)) {
    echo "<p class=\"error\">Please Enter your password</p>";
} else {
    $password = sha1($_POST['password']);
    $password_set = true;
}
if ($username_set == true && $password_set == true) {
    $sql = "SELECT * FROM `users` WHERE `username` = '$username' AND `password` = '$password'";
    $query = mysql_query($sql, $connection);
    $result = mysql_fetch_assoc($query);
    $_SESSION['id'] = $result['id'];
    $_SESSION["user_name"] = $result["username"];
    echo "You are logged in. In a second or two, you`ll be redirected to your profile page";
    header("location:logged-in.php");
}

در واقع کاربران برای ورود به یک ناحیهٔ کاربری فرضی، می‌بایست نام کاربری و رمزعبور خود را وارد فرم فوق نمایند و در صورتی که این کار با موفقیت انجام شود، وارد صفحه‌ای تحت عنوان logged-in.php می‌شوند که حاوی اسکریپت زیر است:


session_start();
if (!$_SESSION['user_name']) {
    header("location:./");
}
$title = "Hi " .  $_SESSION['user_name'] . " you are logged in";
$userID = $_SESSION['id'];
define("TITLE", $title);
include("includes/header.php");
require("includes/db_config.php");

$sql = "SELECT * FROM `users` WHERE `id` = '$userID'";
$query = mysql_query($sql, $connection);
$result = mysql_fetch_assoc($query);

<table>
    <tr>
        <td>ID</td>
        <td>Username</td>
        <td>Password</td>
    </tr>
    <tr>
        <td><?php echo $result['id']; ?></td>
        <td><?php echo $result['username']; ?></td>
        <td><?php echo $result['password']; ?></td>
    </tr>
</table>
<a href="logout.php">Logout</a>

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

 آشنایی با مفهوم SQL Injection در زبان PHP

می‌بینیم که توانستیم با موفقیت وارد ناحیهٔ کاربری شویم. پس از کلیک روی لینک Logout، به فایلی تحت عنوان logout.php ارجاع داده می‌شویم که حاوی اسکریپت زیر است:

session_start();
session_destroy();
define("TITLE", "Logout");
include("includes/header.php");
require("includes/db_config.php");
header("location:./");

در ادامه، قصد داریم تا این وب اپلیکیشن را دور بزنیم؛ برای این منظور خواهیم داشت:

 آشنایی با مفهوم SQL Injection در زبان PHP

همان‌طور که در تصویر فوق مشخص است، به عنوان هم نام کاربری و هم رمزعبور عبارت زیر را وارد کرده‌ایم:


' OR ' 1' = ' 1

حال روی دکمهٔ Login کلیک می‌کنیم:

 آشنایی با مفهوم SQL Injection در زبان PHP

می‌بینیم که بدون آگاهی از نام کاربری و رمزعبور، به راحتی توانستیم این وب اپلیکیشن را دور زده و وارد ناحیهٔ کاربری آن هم از نوع ادمین شویم! در ادامه قصد داریم تا رویکرد فوق را مورد بررسی قرار دهیم تا ببینیم چرا چنین چیزی روی دارد. در واقع، با وارد کردن کد

' OR ' 1' = ' 1

به عنوان نام کاربری و رمزعبور، دستور SQL ما به صورت زیر خواهد بود:


$sql = "SELECT * FROM `users` WHERE `username` = ' ' OR ' 1' = ' 1' AND `password` = ' ' OR ' 1' = ' 1' ";

در زبان SQL مقادیر یک جدول داخل علامت های ' ' قرار می‌گیرند. کدهای فوق بدون قرار دادن مقادیر برای username و password به صورت زیر خواهند بود:

 $sql = "SELECT * FROM `users` WHERE `username` = '  ' AND `password` = '  ' ";

حال زمانی که این عبارت را داخل فیلدهای نام کاربری و رمزعبور قرار می‌دهیم، دستور فوق به صورت زیر در خواهد آمد:

 
$sql = "SELECT * FROM `users` WHERE `username` = ' ' OR ' 1' = ' 1' AND `password` = ' ' OR ' 1' = ' 1' ";

همان‌طور که در کد فوق می‌بینیم، ابتدا مقدار username و یا password را برابر با ' ' قرار داده یعنی تهی، سپس از دستور OR که به معنی «یا» می‌باشد استفاده نموده‌ایم. کاری که این دستور SQL انجام می‌دهد این است که این امکان را به ما می‌دهد تا بتوانیم ۲ مقدار مختلف برای username یا password در نظر بگیریم. مقدار اول که تهی بود و پس از دستور OR هم گفته‌ایم اگر مقدار عدد 1 برابر با 1 بود و از آنجا که جواب این شرط همواره True است، پس این مقدار برای نام کاربری و رمزعبور انتخاب می‌شود.

چنین چیزی اصطلاحاً SQL Injection نامیده می‌شود و برای گرفتن جلوی این نوع حملهٔ سایبری، می‌بایست از متدی تحت عنوان ()mysql_real_escape_string در زبان PHP استفاده کنیم:


session_start();
$username_set = false;
$password_set = false;
$username = $_POST['username'];
$password = $_POST['password'];
//Function to prevent SQL Injection
$secure_password = mysql_real_escape_string($password);
if (empty($username)) {
    echo "<p class=\"error\">Please Enter your username</p>";
} else {
    $username_set = true;
}
if (empty($password)) {
    echo "<p class=\"error\">Please Enter your password</p>";
} else {
    //$password = sha1($_POST['password']);
    $password_set = true;
}
if ($username_set == true && $password_set == true) {
    $sql = "SELECT * FROM `users` WHERE `username` = '$username' AND `password` = '$password'";
    //    $sql = "SELECT * FROM `users` WHERE `username` = ' ' AND `password` = '' OR ' 1' = ' 1' ";
    $query = mysql_query($sql, $connection);
    $result = mysql_fetch_assoc($query);
    $_SESSION['id'] = $result['id'];
    $_SESSION["user_name"] = $result["username"];
    echo "You are logged in. In a second or two, you`ll be redirected to your profile page";
    header("location:logged-in.php");
}

همان‌طور که در کد فوق می‌بینیم، متغیر جدیدی ساخته‌ایم تحت عنوان secure_password$ که مقدار آن را برابر با متد ()mysql_real_escape_string قرار داده و پارامتر قرار داده شده برای این متد، همان متغیر password$ است. از این پس، متد ()mysql_real_escape_string کلیه علائمی همچون ' و غیره که برای نوشتن دستورات SQL مورد استفاده قرار می‌گیرند را حذف می‌نماید لذا هکرها نخواهند توانست تا از طریق فرم‌های اینترنتی به دیتابیس ما و داده‌های آن دسترسی پیدا کنند. اکنون اگر یک بار دیگر عبارت مد نظر را وارد فرم خود کنیم، خواهیم دید که قادر به ورود به ناحیهٔ ادمین نخواهیم بود.



بهزاد مرادی