عکس پیش‌فرض نوشته

در زبان برنامه نویسی PHP روش های متفاوتی برای اتصال به دیتابیس (Database) وجود دارد. در هر روش، خصوصیت ها و ویژگی های خاصی وجود دارد که بسته به نوع کار، میتوانیم روش مورد نظر خود را انتخاب کنیم.

جلوگیری از حملات SQL Injection با PDO در PHP

از روش های اتصال به پایگاه داده در PHP میتوان به دستورات MySQL و MySQLi و PDO اشاره کرد. البته دستورات MySQL در نسخه های جدیدتر PHP دیگر پشتیبانی نمیشود و به نوعی جای خود را به دستورات MySQLi داده اند. (آموزش کار با دیتابیس در PHP با mysqli)

به طور کلی میتوان گفت که PDO برای اتصال به دیتابیس یکی از مناسب ترین گزینه های پیش رو است؛ دلیل آن میتواند سرعت بالا و امکان اتصال آسان به 12 نوع دیتابیس مختلف (نظیر mysql ، sqlite ، oracle ، sqlserver و …) باشد.

در کار با روش PDO و دستورات مربوط به آن، بهتر است با اصول شئ گرایی و برنامه نویسی شئ گرا آشنایی داشته باشید.

برای اتصال به دیتابیس با استفاده از PDO در زبان برنامه نویسی PHP به صورت زیر عمل میکنیم.

<?php
try {

    $connection = new PDO(mysql:host=127.0.0.1; dbname=sabzdanesh_db, "username", "password");
    $result = $connection->query('SELECT * FROM users');
    $data = $result->fetchAll(PDO::FETCH_ASSOC);

} catch (PDOException $e){
   echo $e.getMessage();
}
?>

هماطور که در کد فوق مشاهده میکنید، برای اتصال ابتدا باید یک شئ از نوع PDO بسازیم. سازنده این کلاس در حالت معمول سه ورودی میگیرد: اولین ورودی مشخص کننده میزبان و نام دیتابیس ماست، دومین و سومین آرگومان ورودی نیز نام کاربری و پسورد اتصال به دیتابیس می باشد.

پس از اتصال به دیتابیس، به راحتی و با استفاده از دستورات mysql میتوانیم یک query را اجرا کنیم.

جهت رعایت اصول برنامه نویسی، بهتر است بخش مربوط به اتصال را درون بلوک try catch قرار دهیم تا در صورت بروز ارور بتوان Exception را مدیریت کنیم تا از به وجود آمدن مشکلات غیر منتظره جلوگیری شود.

در این آموزش باد می‌گیریم چطور از حملات sql injection در PHP جلوگیری کنیم. برای این کار از PDO برای کار با دیتابیس استفاده می‌کنیم. اگر مایلید این روش را کامل یاد بگیرید، آموزش PDO در PHP را ببینید.

آموزش PDO در PHP : اتصال به دیتابیس و فراخوانی داده

آموزش PDO در PHP : اتصال به دیتابیس و فراخوانی داده

اکثر اوقات میخواهیم یک query را اجرا کنیم که نیاز است مقادیر درون آن با قرار دادن متغیرهای دیگر تکمیل شود؛ چیزی شبیه دستور زیر:

$sql = "SELECT * FROM users WHERE email = '$email' AND password= '$pass'";

از این نوع پرس و جو (Query) ها در اجرای برنامه ها زیاد استفاده میشود؛ برای مثال جستجوی یک کلمه در مطالب سایت، تایید هویت و ورود یک کاربر، ویرایش اطلاعات (مربوط به کاربر یا مطلب) و …

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

به عنوان مثال اگر ما نتوانیم این نوع حملات را در باکس جستجوی محتوای سایت پیش بینی کنیم، نفوذگر میتواند با اجرای دستورات مورد نظر خود، هر گونه اطلاعاتی را از دیتابیس ما خروجی بگیرد؛ از محتوای جداول گرفته تا اطلاعات کاربران!

در روش PDO برای اتصال به دیتابیس در PHP میتوان با prepare کردن query ها قبل از اجرا شدنشان، دستورات و محتواهای مشکل ساز را بی اثر کرد.

برای اینکه مشخص کنیم کدام مقادیر موجود در query را میخواهیم به صورت یک پارامتر و بدون پیش بینی قبلی وارد دستورات کنیم باید از مفهومی به اسم placeholder در query هایمان استفاده کنیم.

برای فهم بهتر، کد زیر را بررسی کنید؛ دستور زیر همان دستور قبلی است با این تفاوت که متغیرهای آن به صورت Placeholder تعریف شده اند.

$sql = 'SELECT * FROM users WHERE email = ? AND password= ?';

در این حالت بایستی قبل از اجرا کردن دستور، مقادیر مورد نیاز (که با علامت سوال مشخصشان کردیم) را بدهیم.

در PDO از دو نوع placeholder پشتیبانی میشود: موقعیتی (Positional) و تحت نام گذاری (Named)

کد بالا به صورت Positional نوشته شده و کد زیر که معادل کد فوق است به صورت Named Placeholders.

$sql = 'SELECT * FROM users WHERE email = :email AND password= :pass';

با داشتن یک query با placeholder بایستی آنرا با استفاده از متد PDO::prepare() آماده اجرا کینم. این تابع یک statement قابل اجرا روی دیتابیس خواهد داد بدون اینکه دستور مخرب یا غیر منتظره ای درون آن وجود داشته باشد.

در نهایت میتوانیم دستور آماده سازی شده را اجرا کرده و نتایج را دریافت کنیم.

$stmt = $connection->prepare('SELECT * FROM users WHERE email = ? AND password= ?');
$stmt->execute([$email, $pass]);
$user = $stmt->fetch();

اگر placeholder ها را به صورت named تعریف کرده باشیم، کدی مشابه کد زیر خواهیم داشت.

$stmt = $connection->prepare('SELECT * FROM users WHERE email = :email AND password = :pass');
$stmt->execute(['email' => $email, 'pass' => $pass]);
$user = $stmt->fetch();

به عملیات انجام شده فوق، که تعدادی متغیر را وارد دستورات میکند به اصطلاح bind کردن داده ها میگویند.

برای خوانایی بهتر کد و ویرایش راحت تر آن در آینده، میتوانیم ورودی های تابع execute را در متغیر دیگری ذخیره کرده و به عنوان ورودی به متد execute بدهیم.

$stmt = $connection->prepare('SELECT * FROM users WHERE email = ? AND password= ?');
$bind = array($email, $pass);
$stmt->execute($bind);
$user = $stmt->fetch();

با پیاده سازی این روش ساده، میتوانید با امنیت بیشتری با دیتابیس خود در زبان برنامه نویسی PHP کار کنید.

اینکه در هنگام تعریف کردن placeholder ها به کدام روش عمل کنید کاملاً سلیقه ای و بر عهده خودتان است و مزیت یا عیب خاصی ندارند. اما در حالت کلی استفاده از حالت Positional میتواند به کوتاه بودن کد شما کمک کند اما ترتیب ورودی متغیرها در آرایه bind مهم هستند و برعکس؛ در حالت Named کد بیشتری میزنید اما تعریف آرایه bind راحت تر و بعضاً خواناتر خواهد بود.