تأمين سكربت php من أهم الثغرات

Mephistophelesمنذ 8 سنوات

بسم الله الرحمن الرحيم

السلام عليكم ورحمة الله وبركاته

اللهم انفعنا بما علمتنا  وعلمنا بما ينفعنا انك انت العليم الحكيم

في هذا المقال باذن الله ساتكلم عن اهم الثغرات التي يستخدمها المخترقين لاختراق كودك 

الامان هو عامل مهم جدا في اي تطبيق ويب ولا يجب الاغفال عنه, وهذا ما يفعله للاسف بعض المطورين الجدد, سواء بسبب حسن النية او نسيانهم.

سأحاول ان اغطي في هذا المقال الهجمات المستخدمة بتكرار من قبل المخترقين, وبالطبع لا استطيع ان اعدك ان قراءة هذا المقال  ستحمي موقعك من كافة انواع الهجمات لكنها ستوفر لك قدر كافي من الحماية للتصدي لهجمات "اطفال السكربتات", كما تعلمون لا وجود لأمان تام في الانترنت لكن درجة امان الموقع يجب ان تختلف حسب محتواه. فاذا كان هدف الشخص انشاء موقع لبنك مثلا او موقع شراء اونلاين فيجب اخذ الامان بعين الاعتبار التي غالبا ستسبب بطء التطبيق. طبعا ساتحدث عن الامر من منظور لغة php وتحديدا تطبيقات الويب بما انها مجال اختصاصي.

 

تعريف الثغرات:

هي خطأ او نقص في الكود البرمجي يستغله المهاجم لكي يدخل بيانات خبيثة او يوصل لملف ما بغير تصريح.

 

1- حقن قواعد البيانات | SQL Injection 

احد اكثر الثغرات الامنية التي يتم استخدامها,, في البداية يجب توضيح ان قاعدة بيانات mysql يتم برمجتها بعدة اوامر مختلفة ومن  امثلة هذه الاوامر


CREATE TABLE users ;

 

تأتي الثغرة عندما نستقبل بيانات من المستخدم ونقوم بارسالها لقاعدة البيانات وعلى سبيل المثال لنفرض ان سكربت الPHP كتب هكذا 


<?PHP
// نستقبل الاسم المرسل عن طريق ال html form 
$name = $_POST['name'];
//عمل اتصال بالداتابيس
$db = mysql_connect('localhost', 'username', 'password' 'db_name');

// نقوم بعمل كويري بسيط لادخال الاسم المخزن في قاعدة البيانات mysql -
$query = "insert into user values('".$name."')";
// خطوة اخرى لتنفيذ الكويري 
	$insert =$db->query($query);
	

 

بالطبع هذا ليس سكربت مثالي لكن في سبيل الاختصار امتنعت عن كتابة بعض الاشياء 

تطبيق ثغرة sql injection سيكون كمثال ادخال المستخدم في نموذج الhtml بدلا عن اسمه امر برمجي لقواعد بيانات sql على سبيل المثال وليس الحصر


mohamed; drop table users

طبعا سيتعامل مترجم لغة php مع هذا الاسم كاسم عادي ويمرره دون اي مشاكل, ولكن كومبايلر sql سيقوم باضافة اسم mohamed (ما قبل الفاصلة المنقوطة) الى المكان المراد 

ثم سيقوم بتنفيذ باقي الكود كانه كود برمجي وسيقوم بالفعل بحذف جدول users.

مثال اخر وارد الحدوث 

لنفرض مثلا ان لديك فورم تسجيل دخول, والمستخدم لن يستطيع الدخول الا اذا تطابق اسمه مع احد الاسماء المدخلة بالdatabase , صحيح؟

حسنا الكويري المستخدم في هذا المثال يكون شيء مثل الاتي


//عمل جملة كويري بشروط
$query = "SELECT * FROM users WHERE name = '".$name."' )";

كما ترى عزيزي القارئ الكويري يشترط ان يكون الاسم الذي بقاعدة البيانات مطابقا للاسم الذي ادخلة المستخدم والذي تم تخزينه في متغيير name$ بالطبع الكويري لن ينفذ اذا لم يطابق الشرط

لكن يمكن للمخترق ان يتلاعب ويكتب الاتي على سبيل االمثال 

اقتباس

mohamed or 1=1 

بالطبع كلمة or  ستتعامل معها قاعدة البيانات ككلمة مفتاحية وتنفذها, ولو افترضنا ان قاعدة البيانات لم تجد اسم محمد في جداولها ستنتقل للشرط الاخر وهو 1=1 وهو شرط صحيح دائما 

لذلك ستقوم قاعدة البيانات بعرض جميع البيانات من جدول user كما بُرمجت سلفا SELECT * التي تعني "عرض الكل", ستكون الجملة بالنسبة لمحرر sql شيء مثل


SELECT * FROM users WHERE name = mohamed or 1=1;

 

الان بعد ان تعرفنا على خطورة الثغرة وماهيتها ناتي لطريقة تجنبها

  • الجمل المهيأة | Prepared statment 

مكتبة mysql المدمجة تدعم استخدام الجمل المهياة, استخدامها مفيد ليس فقط من ناحية الامان بل حتى في تسريع الكود خصوصا عندما تتعامل مع بيانات كثيرة او مكدسة

والفكرة منها هو ارسال "قالب" فارغ للكويري, ثم ارسال البيانات بعد ذلك بشكل منفصل 


<?php
//عمل اتصال بالداتابيس
$db = mysql_connect('localhost', 'username', 'password' 'db_name');

//انشاء كويري بعلامات استفهام بعدد المدخلات التي سيتم ادخالها 
$query = "insert into employees values(?, ?, ?)";
$stmt = $db->prepare($query);
// وكتابة كل المتغيرات التي تريد ادخالها في الداتابيس  bind_param ا استدعاء الميثود 
//على الترتيب string, string , double  هو توضيح انواع البيانات للبيانات المدخلة  ssd والغرض من كتابة  
$stmt->bind_param("ssd", $name, $last_name, $salary);
// تنفيذ الكويري 
$stmt->execute();

تعتبر الطريقة المذكورة بالاعلى هي الامثل لتجنب هجمات الحقن. بالطبع هناك طرق اخرى من اهمها استخدام دالة mysql_real_escape_string .

 

2- Cross Site Scripting | XSS 

ايضا تعتبر هذع الثغرة من الثغرات ذات الانتشار الواسع,, حيث يظهر خطرها عندما يتم اعادة عرض محتوى تم ادخاله من قبل المستخدمين للتطبيق.

XSS ببساطة هي ثغرة تتيح للمهاحم اضافة اكواد جافاسكربت خبيثة لصفحات html التي يعرضها موقعك, وعندما يقوم الضحية بفتح تلك الصفحات سيُنفذ الكود مباشرة بما انه جافاسكربت front-end

من قبل المتصفح بالطبع, مما يعرضك انت والمستخدمين لخطر من سرقة كوكيز او اعادة توجيه او حتى غلق الصفحة, بالطبع جميعنا نعلم بقوة لغة جافا سكربت

على سبيل المثال, لنفترض اننا نستقبل بياناات لاحد الاعضاء

وسكربت php بسيط سيبدو كالاتي:


<?php

echo $_POST['name'];

وفورم html 


<html>
<body>
<form action="p.php" method="post">
<input type="text" name="name">
<input type="submit">
</form>
</body>
</html>

 

كما هو واضح الكود بسيط جدا فقط لتوضيح الثغرة لكن لك ان تتخيل مثلا ان متغيير  $_POST['data']  هو عبارة عن نبذة شخصية في بروفايل كل عضو

الخطورة تكمن عند اضافة كود جافاسكربت في الحقل الفارغ عند html 

كمثال بسيط 


<script>
  alert('hi, this is xss')
  </script>.

بالطبع المثال هذا يقوم بعرض رسالة منبقة تحوي النص اعلاه بالطبع ستعرض هذه الرسالة عندما يقوم اي شخص بمجرد فتح الصفحة المُصابة بها

حسنا, يبدو انك بدات تدرك ان خطورة الثغرة ليست فقط في عرض رسائل منبثقة, بل تتيح للمهاجم كتابة اي كود جافاسكربت يريد وتنفيذه. كود جافاسكربت يمكن ان يكون قوي جدا في هذه الحالة ومؤذي من سرقة الكوكيز الى اغلاق المتصفح وزرع كيلواجر في متصفح الضحية.

 

لحسن الحظ,, من السهل الحماية ضد هذا النوع من الهجمات, وبما ان الثغرة تنفذ في المتصفح اي بعد ان يُدخل المُخترق كوده الخبيث سنقوم بفلترة "escaping output" او تخطي الحروف المميزة لكي لا يقوم المتصفح بترجمتها واعتبارها String عادي

  • دالة htmlspecialchars

الدالة تاخذ ثلاثة باراميترات اجبارية(وهناك اثنان اختيارية)  كالتالي  :


//تخزين المدخلات في متغير

$unsave_name = $_POST['name'];

// ساشرح هذا السطر بعد قليل

$save_name = htmlspecialchars($unsave_name, ENT_QUOTES, "utf-8");

 

// الدالة تتطلب 3 باراميترات 1-المتغير المحتوي على مدخلات المستخدم 2- نوع التأمين 3-لغة الترميز ويفضل اختيار UTF-8


$save_name = htmlspecialchars($unsave_name, ENT_QUOTES, "utf-8");

ستقوم الدالة بتحويل الرموز المفتاحية لمرادفاتها من الكلمات مثلا <SCRIPT>  ستعرض كالتالي &lt;/script&gt;  وبالتالي ستفقد قيمتها البرمجية ولن تنفذ

شرح انواع التأمين الثلاث:

  1. ENT_COMPAT : سيتم في هذا الننوع تحويل علامات التنصيص الثنائية ( " ) الى الرمز &quot; بينما علامة التنصيص الاحادية ( ' ) لن تتحول.
  2. ENT_QUOTES:  سيتم في هذا الننوع تحويل علامات التنصيص الثنائية ( " ) الى الرمز &quot; بينما علامة التنصيص الاحادية ( ' ) سستحول للرمز &#39
  3. ENT_NOQUOTES: لن يتم تحويل اي قيم.

 

اذا كنت تقوم بجلب مدخلات المستخدم وعرضها بشكل منسق مثلا وهو الارجح غالبا لا احد يعرض صفحة html بدون وسوم او تنسيقات


$unsave_name = "<strong>".$_POST['name']."</strong>";

$save_name = htmlspecialchars($unsave_name, ENT_QUOTES, "utf-8");

ستواجهك مشاكل لان الدالة المذكورة انفا تقوم بتحويل جميع الرموز المفتاحية كذلك < و > , ولن يظهر تنسيق <strong> الذي طبقته. الحل هو ان تستخدم الرموز البديلة &lt; و &gt; يمثلان < و > بالترتيب.

يمكنك ايضا استخدام دالة ()htmlentities لتي تحمل نفس الخصائص وتعمل نفس العمل . وايضا دالة (strip_tags($unsavename .

 

ملاحظة1 : معظم المتصفحات الحديثة لديها حماية ضد xss  لذلك من اراد التجربة فليستخدم internet explorer 

ملاحظة2 : هناك نوع اخر من xss يدعى dom-based xss وهو يعتبر ثغرة تخص جافاسكربت والفرونت ايند بشكل عام لذلك امتنعت عن ذكرها 

 

3- Directory File Listing 

لنفرض ان لديك لديك مجلد يدعى images داخل مسارك الرئيسي www.example.com..  حسنا انت معرض لخطر دخول غير مُصرح لمجلداتك الفرعية

اذا قام احد المستخدمين بكتابة www.example.com/images في المتصفح سيتم اعادة توجيهم نحو المجلد بكافة محتوايته متاحة لهم 

tesr.png

لتجنب ذلك سنقوم بتغيير الاعدادت, غالبا في الاستضافة المشتركة shared hosting لن يكون لديك صلاحية لتعديل ملف php.ini المعني باعدادت لغة php 

بدلا من ذلك ستنشئ في المجلد الرئيسي  ملف باسم

اقتباس

htaccess.

ملاحظة الملف يبدأ بنقطة وبعدها htaccess

وفكرة هذا الملف انه يمكنك من تعديل الاعدادات في المجلد الروت والمجلدات الفرعية منها الخاصة بك فقط

وستقوم باضافة القيمة الاتيه


IndexIgnore *

والتي ستقوم بدورها بمنع الدخول لكافة المجلدات فرعية.

ملاحظة: يوجد اكثر من امر يمكن كتابته يؤدي الى نفس االنتيجة.

 

4-Error reporting

عرض رسائل الاخطاء خاصية مفيدة جدا خصوصا عندما يكون تطبيقك قيد التطوير , المشكلة تأتي عندما يكون  يصبح موقعك متاح للاستخدام

المشكلة لا تكمن في رسائل الاخطاء نفسها فهي ليست مضرة ولن تعرض سكربتك لخطر الاختراق , لكن بعض الاخطاء قد تعرض معلومات قيمة عن تطبيقك كمثال مسار ملف الاتصال بقاعدة البيانات

اذا قمت باي خطأ في طريقة الاتصال على سبيل المثال لا الحصر  , لا تستهن بهذه المعلومات فهي قيمة جدا بالنسة للمخترقين.

مثال بسيط لما يمكن اعرض الاخطاء ان تعرض من معلومات قيمة

اذا قمت بعمل اتصال لقاعدة البيانات عن طريق PDO (Php Data Object) -l بالشكل التالي


<?php 

$conX = new PDO("mysql:host=X;dbname=myDB", "root", "password");

بالطبع X ليس اسم هوست صحيح, فالبتالي سيعرض هذا PHP الى خطأ قاتل FATAL ERROR وسيقوم معالج اللغة بعرض الرسالة التالية 

Warning: PDO::__construct(): php_network_getaddresses: getaddrinfo failed: No such host is known. in C:\xampp\htdocs\rfi\conx.php on line 3

Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: No such host is known. ' in C:\xampp\htdocs\rfi\conx.php:3 Stack trace: #0 C:\xampp\htdocs\rfi\conx.php(3): PDO->__construct('mysql:host=X;db...', 'root', 'password') #1 {main} thrown in C:\xampp\htdocs\rfi\conx.php on line 3

كما هو واضح قام اباتشي بعرض رسالة خطأ منبهاً فيها ان الهوست غير صحيح, نعم ستُعرض هذه الرسالة لمرتادي موقعك اذا حصل خطأ اثناء الاتصال, محتويً على كلمة المرور واسم الادمن وحتى اسم قاعدة البيانات نفيها مما يجعل امر اختراقها امر سهل جدا اذا حصل. ربما انت لن تقوم بخطأ مثل كتابة اسم هوست خاطئ لكن المخترقين لذيهم طرقهم في "اجبار اباتشي على عرض رسالة خطأ" لذلك من الافضل اغلاق عرض الاخطاء

 

لحسن الحظ يمكن تدارك الامر بسهولة حيث يمكنك تعديل هذه القيم عن طريق ملف php.ini 

display_errors : Off

بالطبع هذه القيمة تحدد ما اذا كان php سيرسل رسائل الاخطاء للشاشة ام لا. بالطبع اذا كان تطبيقك قيد التطوير يفضل تركها on لكن عند نشر موقعك  للعامة يفضل اغلاقها .

واذا لم تكن صاحب السيرفر يمكنك كما ذكرت انفا ان تنشئ ملف htaccess.  بالقيم التالية 


php_flag display_errors off

 

قيم اخرى ذات علاقة 

error_reporting : تحدد عن طريقها ماهي الاخطاء التي يجب ان تعرض ويفصل تركها كما هي E-ALL

 log_errors  : هذه القيم تحدد ما اذا كانت الاخطاء ستسجل في ملف لمراجعته لاحقا ينصح بتركها ON دائما

error_log : تحديد مسار الملف الذي ستسجل الاخطاء فيه

اذا لم يكن لديك صلاحية لملف php.ini يمكن اضافة القيم التالية في ملف htaccess.

php_flag error_reporting 8191
php_flag log_errors on
php_flag error_log /htdocs/myApp/logs_error.log

 

يمكنك ايضا اضافة 


error_reporting(0);

لكود php الذي تكتبه 

 

نصائح عامة :

1.لا تثق في المُستخدم 

قد يبدو كلامي وقح بعض الشيء, لكن عندما تفتح موقعك للعامة انت لا تدري من قد يحاول الولوج لموقعك. ليس كل الناس بالطيبة التي تظن.

قم بالتاكد من مدخلات المستخدم وفلترتها مهما كانت بسيطة, فمثلا عند عمل فورم بالشكل التالي 

l.png

بالكود البسيط التالي 


<p> what is your gender 
<form action="pr.php" method="post" > 
<input type="radio" name="male" > Male
<input type="radio" name="female" > Female
<input type="submit" >
</form>

حسنا,, ولنفترض ان برمجة سكربت الphp تمت بالطريقة التالية لاستقبال النتائج :


<?php

if ($_POST['male']) 
		echo "you are a male";
elseif ($_POST['female'])
		echo "you are female";

 

على الرغم من انهم خيارين ولا ثالث لهم radio buttons الا ان بها ثغرة, حيث يمكن لاحد المخترقين ان يقوم بإتصال مباشر مع سكربت php ويقوم بارسال قيم غير المحددة ذكر وانثى في حالتنا

كما تعلم عزيزي القارئ بما اننا نستخدم بروتوكول http والذي هو بروتوكول نصي بسيط, لنفرض ان المستخدم اختار male سترسل رسالة لسيرفر الموقع (http)  على الصيغة الاتية تقريبا:

POST /pr.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.1)
Gecko/2008070208 Firefox/3.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 11
Content-Type: text/html; charset=male

 

حسنا,, يمكن للمخترق ان يقوم باتصال telnet لسيرفرك ويرسل رسالة مشابهه للنص السابق لنفرض مثلا كالاتي 

POST /pr.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.1)
Gecko/2008070208 Firefox/3.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 11
Content-Type: text/html; charset=drop table users

 

بالطبع سيقوم السيرفر  بمعالجة البيانات واذا لم نقم بكتابة كود امن بشكل كافي فربما نتعرض لخطر sql injection اذا كانت البيانات تدخل مباشرة لقاعدة البيانات.

ملاحظة في المثال المذكور اعلاه لا يوجد ادخال في قاعدة البيانات, لكن افترض اسوا الحالات

 

الحل الامثل لمثل هذه الحالة, ببساطة اضافة هذا السطر لنهاية الكود :


else 
	exit();

فانت بهذا تكون قد حددت الحالتين الرئيسيتين وفي حال حصول اي حالة اخرى سيقوم السكربت باغلاق نفسه exit(); تجنبا للهجمات.

 

  • قم بفلترة كافة مدخلات المستخدم بالدوال المذكورة انفاً.
  • قم بانشاء اكثر من ادمن لقاعدة البيانات بصلاحيات مختلفة, عند انشاء اتصال لا تتصل عن طريق الروت دائما. فاذا كان الغرض من الاتصال اضافة بيانات جديدة فقط فقم باستخدام الاكاونت الذي لديه صلاحية الinsert فقط وهكذا دواليك.
  • تحقق حتى من ابسط المدخلات والحالات, تذكر قاعدة بيانات mysql حساسة جدا وادخال بيانات خاطئة بها قد يسبب مشاكل حقيقية لك,
  • تأكد من النص المدخل ليس فارغ اذا كان الحقل المقابل في قاعدة البيانات not null
  • تاكد من ان النص لا يتجاوز عدد الحروف المسموح به في قاعدة البيانات.
  • (اختياري) تأكد من ان النص لا يحتوي على الرموز الغريبة مثل #$%*@: وغيرها يمكن ان تحقق هذا ببساطة باستخدام التعابير القياسية.

 لاختبار تطبيقك ينصح بتجربة جميع الاخطاء المذكورة فيه لترى بنفسك,

كمثال :

  • يمكنك ان تدخل بيانات مثل delete table users; في تطيقك
  • جرب ان تدخل بيانات مثل $%%#@@ 
  • جرب ان تدخل نوع بيانات غير المحددة في قاعدة البيانات كادخال احرف لاتينية مثلا في حقل من نوع date.
  •  

صل الله وسلم على سيدنا محمد وعلى اله وصحبه اجمعين. 

بحمد الله انتهيت من ذكر اكثر اربع هجمات شيوعا واغلبها متعلقة بالكود البرمجي, باذن الله في الموضوع القادم ساكتب عن اربع ثغرات اخرى باذن الله.

كلمات دليلية:
11
إعجاب
15924
مشاهدات
0
مشاركة
0
متابع
متميز
محتوى رهيب

التعليقات (1)

Muneera_salah:

جزاك الله خيرا مقال قيم بارك الله فيك

 

لايوجد لديك حساب في عالم البرمجة؟

تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !