23
تشکر

نحوه کار با PDO و دفع SQL Injection از طریق آن

نحوه کار با PDO و دفع SQL Injection از طریق آن

نحوه کار با PDO و دفع SQL Injection از طریق آن

این مطلب در دسته بندی مطالب پی اچ پی است. پی اچ پی را در اینجا دنبال کنید.

در مطالب گذشته در مورد امنیت در PHP در مورد حمله SQL Injection صحبت کردیم. و گفتیم میتوان با استفاده از PDO برای دفع این حملات استفاده کرد. در این مطلب با نحوه کار با PDO آشنا میشویم. سعی کنید از این به بعد در پروژه ها از PDO استفاده کنید.

شما احتمالا همیشه برای نمایش تعدادی رکورد از دیتابیس به صورت زیر به دیتابیس متصل میشدید و رکوردها را نمایش میدادید:

$connection=@mysql_connect($host,$user_name,$pass_word) or die(mysql_error());
$dbConnection=mysql_select_db($db_name,$connection) or die(mysql_error());
$query="insert into p5
                    (id,name,num_of_stu) values
                    ('".$id."','".$name."','".$num_of_stu."')";
$result=mysql_query($query);

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

خب برای اتصال به دیتابیس در PDO مانند کد زیر عمل میکنیم:

//$db = new PDO('نوع دیتابیس: host=آدرس هاست دیتابیس; dbname=نام دیتابیس; charset=نوع کدگذاری', 'Username', 'Password');
$db = new PDO('mysql:host=localhost; dbname=aparnet_db; charset=UTF8', 'root', '1234');

حالا که به دیتابیس متصل شده ایم میتوانیم کوئری بر روی دیتابیس انجام دهیم. نحوه کوئری برای دفع حملات SQL Injection باید به طریق زیر باشد:

$sql = "INSERT INTO users (username, password) VALUES (:user, :pass)";
$stmt = $db->prepare($sql);
$stmt->execute(array(
    ":user"=>$user,
    ":pass"=>$pass
));

در خط اول ما مانند دفعات قبل دستور کوئری را نوشتیم. اما به جای قراردادن مقادیر اصلی یک لیبل گذاشتیم که ابتدای آن دارای : است. در خط دوم کوئری بالا را آماده عملیات میکنیم. و در خط سوم مقادیر اصلی متغییرها را درون لیبل ها جایگزین میکنیم.

در کد زیر هم یک مثال برای گرفتن اطلاعات از دیتابیس است.

$stmt = $db->query('SELECT * FROM users');
 
foreach($stmt as $row){
    echo "User : " . $row['username'];
    echo "   Pass : " . $row['password'] . "<br />";
}

برای اطلاعات بیشتر در مورد PDO به اینجا مراجعه کنید.

 

    • محسن شفیعی می‌گه:

      اگر بخوایم بر اساس پاسخ اول بگیم. prepare در PDO جلوی حملات 1nd رو میگیره اما نمیتونه جلوی حملات 2nd رو بگیره، که توضیح این حملات در همون متن اشاره شد.
      اگر بخوایم این پست رو کاملتر بگیم باید در زمان نمایش اطلاعات و یا استفاده دوباره اونها به هر نحوی با استفاده از توابع موردنظر آنها را prepare کنیم.
      ممنون از شما

    • almas می‌گه:

      بله همینطوره و میشه از htmlpurifier استفاده کرد، یک سؤال داشتم:
      تیبل settings من یه فیلد به نام setsactive داره که یا مقدار 0 میگیره یا مقدار 1 و این مقادیر معلومه و توسط کاربران وارد نمیشه، فقط براشون نمایش داده میشه

      آیا نیاز به پارامتری کردن دارم و اینکه چطور بر اساس سینتکس pdo یه کوئری بنویسم که:

      سطرهایی که فیلد setsactiveشون مقدار 0 داره جدا rowCoun بشن و سطرهایی که فیلد setsactiveشون با مقدار 1 داره جدا rowCoun بشن؟
      $stmt = $conn->prepare(‘SELECT setsid, setsname, setsactive, setstype
      FROM settings WHERE setsactive = ?’);
      .
      .
      .
      و اینکه از ? استفاده کنم یا :
      باتشکر

    • محسن شفیعی می‌گه:

      اگه حتی خود مقدار صفر یا یک رو هم از کاربر میگیرید که بهتره پارامتری بشه در غیر اینصورت لزومی نداره و یادتون نره داخل دیتابیس این فیلد رو Boolean کنید.
      در مورد rowCount شما یا میتونید دوبار کوئری انجام بدید یا از کوئری زیر استفاده کنید.
      SELECT * FROM (
      select count(id) as setsactive0 from settings where setsactive = 0
      ) as setsactive0, (
      select count(id) as setsactive1 from settings where setsactive = 1
      ) as setsactive1
      در سوال آخرتون با : آشنایی ندارم.

    • almas می‌گه:

      ممنون بابت پاسخ
      فکر کنم این کوئری بهتر باشه
      SELECT setsactive, count(*) cnt FROM settings GROUP BY $setsactive

      http://sqlfiddle.com/#!2/907c2/1

      اما چطور اطلاعات را چاپ کنم
      جمع تعداد فیلدهای setsactive با مقدار صفر اینقدر
      و جمع فلان تعداد setsactive با مقدار یک 1
      تشکر

  • ali می‌گه:

    سلام.روش اولی چه اشکالی داره ؟

  • حمید می‌گه:

    خوب بود
    از شر اینجکشن راحت شدیم


  • نظرات این مطلب بسته است.