الموضوعات التي يتم تناولها
التعامل مع نقاط ضعف أمان قاعدة البيانات
لزيادة الأمان في Dreamweaver 8.0.2 وCS3، قمنا بإزالة القدرة على استخدام معلمات Dynamic SQL داخل مجموعات السجلات القياسية. كانت التعليمات البرمجية الأصلية تعرّض قواعد البيانات لعمليات حقن SQL. أدى استخدام العبارات الجاهزة لطرازات خادم ASP_VBS وColdFusion إلى التعامل مع نقاط الضعف الأمنية. وقد كان من الضروري إضافة دالة إلى الصفحة التي يتم تطبيق مجموعة السجلات الأولى عليها ثم استدعاء هذه الوظيفة من كل مجموعات السجلات في صفحة PHP_MySQL. وهذا الأسلوب يشبه العبارات الجاهزة في ASP_VBS وColdFusion.
في سياق الجهد المبذول لإغلاق نقطة الضعف الأمنية، قمنا بالتضحية ببعض المرونة لضمان الأمان. نود أن نعطي المطورين الذين لديهم بالفعل امتدادات أو الذين يخططون لتطويرها والتي يجب أن تقوم بالتعامل مع استعلامات SQL الديناميكية؛ بالإضافة إلى المستخدمين النهائيين الذين يرغبون في تخصيص مجموعات السجلات الخاصة بهم لقبول المعلمات الديناميكية؛ القدرة على تحرير مجموعات السجلات المخصصة هذه من داخل Dreamweaver.
أساليب حقن ومنع SQL
حقن SQL هو أسلوب يستفيد من نقاط الضعف الأمنية التي تحدث في طبقة قاعدة البيانات في التطبيق. تكون نقطة الضعف موجودة عندما تتم تصفية مدخلات المستخدم بشكل غير صحيح لحروف الهروب الحرفية للسلسلة المضمنة في عبارات SQL أو لا تتم كتابة مدخلات المستخدم بشكل قوي وبالتالي يتم تنفيذها بشكل غير متوقع. في الواقع هي عبارة عن مثيل لفئة أكثر عمومية لنقاط الضعف التي يمكن أن تحدث عندما يتم تضمين لغة برمجة أو برامج نصية داخل غيرها. الرجاء زيارة Wikipedia للحصول على المزيد من المعلومات.
مثال على استعلام SQL قياسي:
SELECT * FROM company_com WHERE name_com = '$companyName'
في المثال الوارد أعلاه، تتم قراءة متغير $companyName من حقل نموذج إدخال، وبالتالي يكون للمستخدم السيطرة التامة على القيمة التي يتم تقديمها. في أفضل السيناريوهات، عندما يقوم المستخدم بإدخال "Adobe" (بدون علامات الاقتباس) في المدخلات التي تطابق اسم الشركة، يأخذ استعلام SQL الشكل التالي:
SELECT * FROM company_com WHERE name_com = 'Adobe'
إلا أنه تكون هناك حالات قد يرغب المستخدمون فيها في اقتحام موقع الويب وسرقة المعلومات الحساسة و / أو تدمير قاعدة البيانات. مع وضع المثال الوارد أعلاه في الاعتبار، يكون من السهل حقن SQL من خلال إدخال السلسلة التالية "blabla' OR '1'='1" (بدون علامات الاقتباس المحيطية). من خلال كتابة تسلسل الحروف هذا، يتاح للمستخدم الوصول إلى كل الشركات بدلاً من شركة واحدة. تعليمات SQL البرمجية الفعلية التي يتم تنفيذها هي:
SELECT * FROM company_com WHERE name_com = 'blabla' OR '1'='1'
بالإضافة إلى ذلك، إذا كان المستخدم يرغب في حذف جدول company_com كله، يمكنه فعل ذلك بكل بساطة من خلال تمرير السلسلة التالية "x'; DROP TABLE company_com; --" (بدون علامات الاقتباس المحيطية). إليكم استعلام SQL الكامل:
SELECT * FROM company_com WHERE name_com = 'x'; DROP TABLE company_com; --'
استخدم أحد الإجراءات الواردة أدناه لحماية موقع الويب من عمليات حقن SQL:
- قصر الإدخال على حد أدنى من الحروف المسموح بها من خلال إزالة كل الحروف الأخرى التي تتواجد خارج النطاق المحدد بشكل تلقائي.
- هروب كل الحروف التي يمكن أن تسبب مشكلات عندما يتم استخدامها داخل استعلام SQL (على سبيل المثال، حروف اقتباس مفردة).
- استخدام العبارات الجاهزة.
- استخدام حقوق الوصول إلى قاعدة البيانات.
- استخدام الإجراءات المخزنة.
نوصي باستخدام العبارات الجاهزة الموصوفة بمزيد من التفاصيل في استخدام العبارات الجاهزة. يستخدم Dreamweaver 8.0.2 وCS3 منهجية العبارات الجاهزة لطرازات الخادم ASP_VBS وASP_JavaScript وCold Fusion وJSP، ومنهجية هروب مدخلات المستخدم لنموذج خادم PHP_MySQL. الرجاء الرجوع إلى هجمات حقن SQL كمثال للحصول على المزيد من المعلومات حول هجمات حقن SQL.
استخدام العبارات الجاهزة
يستخدم Dreamweaver 8.0.2 وCS العبارات الجاهزة حيث إن هذا الحل يضمن لنا تنفيذ استبدال معلمات SQL الفعلية واستخدام القيم المحددة (التي ربما يتم إرسالها عبر عنوان URL) على الخادم وليس على الصفحة. كما تضمن العبارات الجاهزة كذلك أن تحتوي القيمة التي يتم تمريرها إلى SQL ذاتها على نوع البيانات المناسب وتستخدم الهروب المناسب (إذا قيل أن المعلمة من نوع "رقم"، فلن يكون المستخدم قادرًا على إرسال حرف، أو إذا كانت المعلمة من نوع "نص"، فعلى الأرجح حينها أن يتم تنفيذ الهروب على السلسلة الكاملة التي يتم تمريرها بالشكل الصحيح، ولن تتاح للمستخدم الفرصة لتنفيذ حقن SQL).
العبارات الجاهزة لطرازات خادم ASP_VBS وASP_JS
بالنسبة لطرازات الخادم ASP_VBS وASP_JS، نحن نعتمد على طبقة قاعدة البيانات ADODB. يوضح المثال التالي مجموعة سجلات ASP_VBS بسيطة تستخدم معلمة SQL ديناميكية لتصفية النتائج.
... <% Dim Recordset1__MMColParam Recordset1__MMColParam = "1" If (Request.QueryString("id_com") <> "") Then Recordset1__MMColParam = Request.QueryString("id_com") End If %> <% Dim Recordset1 Dim Recordset1_cmd Dim Recordset1_numRows Set Recordset1_cmd = Server.CreateObject ("ADODB.Command") Recordset1_cmd.ActiveConnection = MM_connContacts_STRING Recordset1_cmd.CommandText = "SELECT * FROM company_com WHERE id_com = ?" Recordset1_cmd.Prepared = true Recordset1_cmd.Parameters.Append Recordset1_cmd.CreateParameter("param1", 5, 1, -1, Recordset1__MMColParam) ' adDouble Set Recordset1 = Recordset1_cmd.Execute Recordset1_numRows = 0 %> ...العبارات الجاهزة لطراز خادم ColdFusion
يوفر ColdFusion الدعم المدمج للعبارات الجاهزة. يوضح المثال التالي مجموعة سجلات ColdFusion بسيطة تستخدم معلمة SQL ديناميكية لتصفية النتائج.
... <cfparam name="URL.id_com" default="1"> <cfquery name="Recordset1" datasource="company_employee"> SELECT * FROM company_com WHERE id_com = <cfqueryparam value="#URL.id_com#" cfsqltype="cf_sql_numeric"> </cfquery> ...العبارات الجاهزة الخاضعة للمحاكاة لطراز خادم PHP_MySQL
أصبحت العبارات الجاهزة لـ PHP مع MySQL 4.1، إلا أننا نظرًا لأننا كنا نرغب في دعم الإصدارات السابقة من MySQL كذلك، قررنا تنفيذ وظيفة مخصصة تقوم بعمل نفس الشيء تقريبًا. يوضح المثال التالي مجموعة سجلات PHP بسيطة تستخدم معلمة SQL ديناميكية لتصفية النتائج.
... <?php if (!function_exists("GetSQLValueString")) { function GetSQLValueString($theValue, $theType, $theDefinedValue = "", $theNotDefinedValue = "") { $theValue = get_magic_quotes_gpc() ? stripslashes($theValue) : $theValue; $theValue = function_exists("mysql_real_escape_string") ? mysql_real_escape_string($theValue) : mysql_escape_string($theValue); switch ($theType) { case "text": $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL"; break; case "long": case "int": $theValue = ($theValue != "") ? intval($theValue) : "NULL"; break; case "double": $theValue = ($theValue != "") ? "'" . doubleval($theValue) . "'" : "NULL"; break; case "date": $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL"; break; case "defined": $theValue = ($theValue != "") ? $theDefinedValue : $theNotDefinedValue; break; } return $theValue; } } $colname_Recordset1 = "-1"; if (isset($_GET['id_com'])) { $colname_Recordset1 = $_GET['id_com']; } mysql_select_db($database_connContacts, $connContacts); $query_Recordset1 = sprintf("SELECT * FROM company_com WHERE id_com = %s", GetSQLValueString($colname_Recordset1, "int")); $Recordset1 = mysql_query($query_Recordset1, $connContacts) or die(mysql_error()); $row_Recordset1 = mysql_fetch_assoc($Recordset1); $totalRows_Recordset1 = mysql_num_rows($Recordset1); ?> ...السماح بالمعلمات الديناميكية في مجموعات السجلات القياسية
حسنًا، كيف يمكننا الحماية من عمليات حقن SQL مع السماح في نفس الوقت بالمعلمات الديناميكية مع الحفاظ على كون التعليمات البرمجية الناجمة قابلة للتحرير عبر لوحة "سلوكيات الخادم" في Dreamweaver؟ والحل يتمثل في إدراج المعلومات الديناميكية في استعلام SQL ذاته، بدلاً من تمريرها كمعلمات SQL كلاسيكية (والتي يمكن أن يتم تنفيذ الهروب عليها أو إلحاقها بتعليمات SQL عبر العبارات الجاهزة).
مهم: لا يمكن للمستخدمين إنشاء تلك التعليمات البرمجية باستخدام "سلوكيات الكائنات والخادم" والتي يتم تضمينها بشكل مدمج مع Dreamweaver 8.0.2 أو CS3 (على سبيل المثال: إدخال مجموعة سجلات عبر لوحة "سلوكيات الخادم" أو شريط "الإدراج"). يتطلب هذا الحل أن يقوم المستخدم بتحرير التعليمات البرمجية يدويًا، أو أن يقوم بتثبيت امتداد من جهة خارجية تقوم بإنشاء تلك التعليمات البرمجية. تقع مسؤولية كتابة التعليمات البرمجية الآمنة على عاتق المستخدم أو مطور برامج الجهة الخارجية.
الغرض من هذه الطريقة السماح للمطورين أصحاب الخبرات بإنشاء استعلامات SQL ديناميكية. يعطي إساءة استخدام هذا الحل للقراصنة إمكانية الحصول على امتيازات غير مرغوب فيها و / أو اختراق صفحات الويب وقاعدة البيانات. الرجاء الرجوع إلى أساليب حقن ومنع SQL للحد من الخطر المقترن بعمليات حقن SQL.
الحالات الرئيسية التي حددنا أنه يمكن استخدام هذا الحل معها هي:
- إنشاء / تحديث استعلام SQL بشكل يدوي لقبول المعلمات الديناميكية.
- إنشاء / تحديث الامتدادات الحالية من أجل إنشاء المعلمات الديناميكية.
سيتم توضيح كلا حالتي الاستخدام بالتفاصيل في الفقرات التالية.
إنشاء / تحديث استعلام SQL يدويًا لقبول المعلمات الديناميكية مع إبقاء مجموعة السجلات قابلة للتحرير من داخل Dreamweaver
في المثال التالي، يريد المستخدم إضافة وظيفة الفرز إلى جدول ديناميكي. ويقرر إعادة تحميل الصفحة أثناء تمرير الملفات واتجاه الفرز المطلوب استخدامه (تصاعديًا أو تنازليًا) في عنوان URL. إليك مثال URL المبدئي:
http://www.mydomain.com/index.php?sortCol=name_com&sortDir=ascيلزم عمليات التعليمات البرمجية باليد لإنجاز هذه المهمة في Dreamweaver باستخدام "سلوكيات الخادم". توضح نماذج التعليمات البرمجية التالية التغييرات التي يجب إجراؤها لكل طراز خادم.
مهم: يرجى ملاحظة أن أيا من الأمثلة أدناه ليس لها صلاحية ضد عمليات حقن SQL. إن دورها تثقيفي بحت ويجب عدم استخدامها في الإنتاج كما هي. الأمثلة ليست واقية تمامًا بما يمكن أن يجعلها بسيطة قدر الإمكان. بل يجب أن تحمي ضد عمليات حقن SQL. الرجاء الرجوع إلى أساليب حقن ومنع SQL للحصول على المزيد من المعلومات.
ASP_VBS
قبل:
... <% Dim Recordset1 Dim Recordset1_cmd Dim Recordset1_numRows Set Recordset1_cmd = Server.CreateObject ("ADODB.Command") Recordset1_cmd.ActiveConnection = MM_connContacts_STRING Recordset1_cmd.CommandText = "SELECT * FROM company_com" Recordset1_cmd.Prepared = true Set Recordset1 = Recordset1_cmd.Execute Recordset1_numRows = 0 %> ...بعد:
... <% Dim orderBy: orderBy = "" If (Request.QueryString("sortCol") <> "") Then orderBy = "ORDER BY " & Request.QueryString("id_com") If (Request.QueryString("sortDir") <> "") Then orderBy = orderBy & " " & Request.QueryString("sortDir") End If End If %> <% Dim Recordset1 Dim Recordset1_cmd Dim Recordset1_numRows Set Recordset1_cmd = Server.CreateObject ("ADODB.Command") Recordset1_cmd.ActiveConnection = MM_connContacts_STRING Recordset1_cmd.CommandText = "SELECT * FROM company_com " & orderBy & "" Recordset1_cmd.Prepared = true Set Recordset1 = Recordset1_cmd.Execute Recordset1_numRows = 0 %> ...ColdFusion
قبل:
... <cfquery name="Recordset1" datasource="company_employee"> SELECT * FROM company_com </cfquery> ...بعد:
... <cfparam name="URL.sortCol" default=""> <cfparam name="URL.sortDir" default="ASC"> <cfset orderBy=""> <cfif (#URL.sortCol# NEQ "")> <cfset orderBy="ORDER BY #URL.sortCol# #URL.sortDir#"> </cfif> <cfquery name="Recordset1" datasource="company_employee"> SELECT * FROM company_com #orderBy# </cfquery> ...PHP_MySQL
قبل:
... <?php mysql_select_db($database_connContacts, $connContacts); $query_Recordset1 = "SELECT * FROM company_com"; $Recordset1 = mysql_query($query_Recordset1, $connContacts) or die(mysql_error()); $row_Recordset1 = mysql_fetch_assoc($Recordset1); $totalRows_Recordset1 = mysql_num_rows($Recordset1); ?> ...بعد:
... <?php $orderBy = ""; if (isset($_GET['sortCol'])) { $orderBy = "ORDER BY " . $_GET['sortCol']; if (isset($_GET['sortDir'])) { $orderBy .= " " . $_GET['sortDir']; } } ?> <?php mysql_select_db($database_connContacts, $connContacts); $query_Recordset1 = "SELECT * FROM company_com " . $orderBy . ""; $Recordset1 = mysql_query($query_Recordset1, $connContacts) or die(mysql_error()); $row_Recordset1 = mysql_fetch_assoc($Recordset1); $totalRows_Recordset1 = mysql_num_rows($Recordset1); ?> ...قم بإنشاء / ترقية الامتدادات الموجودة لإنشاء معلمات ديناميكية مع الحفاظ على مجموعة السجلات قابلة للتحرير من داخل Dreamweaver
ضع في اعتبارك الآن نفس السيناريو كما هو موضح أعلاه، باستثناء أن المستخدم يريد إنشاء امتداد سينتج التعليمات البرمجية المناسبة بدلاً من الاعتماد على مجموعة من الوظائف المدمجة والتحرير اليدوي. يجب أن ينشئ الامتداد الجديد التعليمات البرمجية الصحيحة لنماذج خادم ASP_VBS وColdFusion وPHP_MySQL.
مهم: سوف نركز في الأقسام التالية فقط على إنشاء التعليمات البرمجية التي ستستخدم القيم من معلمات URL لإنشاء استعلام SQL ديناميكي. ينصب التركيز الرئيسي على إنشاء التعليمات البرمجية بحيث لا يزال بإمكان Dreamweaver التعرف عليها والتي تصبح قابلة للتحرير من خلال واجهات Dreamweaver القياسية. لن يتعامل هذا البرنامج التعليمي مع التحقق من صحة بيانات الإدخال (عبر معلمات URL) أو حماية SQL النهائية ضد أي محاولة لحقن SQL لأن تعقيد هذه التعليمات البرمجية يقع خارج نطاق هذا البرنامج التعليمي. المطور هو المسؤول الوحيد عن حماية SQL النهائية ضد حقن SQL.
نقدم امتدادًا تجريبيًا يأخذ الاتصال والجدول كمدخلات وينشئ جدولًا ديناميكيًا يعرض جميع السجلات. يقوم أيضًا بتحديث SQL التي تم إنشاؤها لاحتواء متغير orderBy كما هو موضح في الأمثلة أعلاه. تم تصميم الامتداد لـ Dreamweaver 8.0.2 و CS3. التعليمات البرمجية التي تم إنشاؤها ليست واقية تمامًا، لأن الهدف هو إنشاء مجموعات سجلات تحتوي على معلمات ديناميكية تظل قابلة للتحرير باستخدام واجهات Dreamweaver القياسية. توجد التعليمات البرمجية المصدرية للامتداد في مجلد تهيئة المستخدم.
في جميع أمثلة التعليمات البرمجية أدناه، تمت إضافة الأقسام المميزة لتمكين وظيفة الفرز عبر معلمتي عناوين URL sortCol وsortDir.
ASP_VBS
توجد التعليمات البرمجية التي تنشئ استعلام SQL المناسب لنموذج خادم ASP_VBS في الملف "[USER_CONFIGURATION_FOLDER]/Commands/My Dynamic Table.js" في مجلد تهيئة المستخدم. التغيير الجدير بالملاحظة موجود في السطر 130:
... 130: paramObj.encodedSQL = "SELECT * FROM " + paramObj.table + " \" & orderBy & \""; ...يتضمن ملف المشاركين لسلوك خادم MyDynamicTable ASP_VBS مشاركًا إضافيًا يضيف تعريف متغير "orderBy" إلى الصفحة:
<group name="MyDynamicTable" version="9.0"> <groupParticipants> <groupParticipant name="connectionref_statement" /> <groupParticipant name="MyDynamicTable_orderBy" /> <groupParticipant name="recordset_main" /> <groupParticipant name="repeatedRegion_init2" /> <groupParticipant name="DynamicTable_main" /> <groupParticipant name="recordset_close" /> </groupParticipants> </group>ColdFusion
يحتوي نفس الملف "[USER_CONFIGURATION_FOLDER]/Commands/My Dynamic Table.js" في مجلد تهيئة المستخدم أيضًا على التعليمات البرمجية لطراز خادم ColdFusion؛ التغيير ذو الصلة في هذه الحالة موجود في السطر 138:
... 138: paramObj.SQLStatement = "SELECT * FROM " + paramObj.table + " #orderBy#"; ...يتضمن ملف المشاركين لسلوك خادم MyDynamicTable ColdFusion مشاركًا إضافيًا يضيف تعريف متغير "orderBy" إلى الصفحة:
<group name="MyDynamicTable" version="9.0"> <groupParticipants> <groupParticipant name="MyDynamicTable_orderBy" /> <groupParticipant name="Recordset_main" /> <groupParticipant name="DynamicTable_main" /> <groupParticipant name="RepeatedRegion_pageNum" /> <groupParticipant name="RepeatedRegion_maxRows" /> <groupParticipant name="RepeatedRegion_startRow" /> <groupParticipant name="RepeatedRegion_endRow" /> <groupParticipant name="RepeatedRegion_totalPages" /> </groupParticipants> </group>PHP_MySQL
آخر نموذج خادم في الامتداد هو PHP_MySQL. التغيير ذو الصلة في الملف "[USER_CONFIGURATION_FOLDER]/Commands/My Dynamic Table.js" في مجلد تكوين المستخدم موجود في السطر 122:
... 122: paramObj.SQLStatement = "SELECT * FROM " + paramObj.table+ " \" . $orderBy . \""; ...يتضمن ملف المشاركين لسلوك خادم MyDynamicTable PHP_MySQL مشاركًا إضافيًا يضيف تعريف متغير "orderBy" إلى الصفحة:
<group name="MyDynamicTable" version="9.0"> <groupParticipants> <groupParticipant name="Connection_include" /> <groupParticipant name="MyDynamicTable_orderBy" /> <groupParticipant name="EditOps_SQLValueString" /> <groupParticipant name="Recordset_main" /> <groupParticipant name="DynamicTable_main" /> <groupParticipant name="Recordset_close" /> </groupParticipants> </group>الايجابيات
تتميز الطريقة الموضحة أعلاه بالعديد من المميزات، بما في ذلك:
- يمكن للمطورين الأكثر تقدمًا الاستفادة من نقطة ضعف حقن SQL لإنشاء SQL أكثر تعقيدًا بشكل ديناميكي.
- ستظل مجموعات السجلات التي تم إنشاؤها قابلة للتحرير من داخل Dreamweaver.
- ليس من الصعب الدمج في امتدادات Dreamweaver الحالية التي تنشئ مجموعات سجلات بمعلمات SQL ديناميكية.
- تظل التعليمات البرمجية الافتراضية التي تم إنشاؤها بواسطة Dreamweaver بدون تغيير؛ يمكن للمطورين الذين لا يحتاجون إلى استعلامات ديناميكية (وعملائهم) التأكد من أن التعليمات البرمجية التي كتبها Dreamweaver آمنة.
السلبيات
نظرًا لأن Dreamweaver لم يتم تصميمه افتراضيًا لدعم هذه الطريقة، فإنه يضم أيضًا على بعض العيوب، بما في ذلك:
- التعليمات البرمجية التي يتم إنشاؤها باستخدام الطريقة الموضحة في هذه الوثيقة عرضة لحقن SQL، وبالتالي تحتاج إلى الحماية بطرق أخرى. تتضمن قائمة طرق الحماية هذه على سبيل المثال لا الحصر:
- التأكد من أن المستخدم النهائي لا يمكنه استخدام طريقة حقن SQL لتعريض صفحة الويب و / أو قاعدة البيانات للخطر؛
- استخدام طريقة هروب الوسائط قبل أن تصل إلى SQL الفعلية؛
- التأكد من أنه حتى إذا تمكن المستخدم من اختراق التعليمات البرمجية الخاصة بك، فلن يتمكن من سرقة معلومات حساسة و / أو لن يتمكن من تعريض قاعدة البيانات للخطر.
- هناك مشكلتان معروفتان لا يمكن حلهما حتى يتم إصدار الإصدار التالي من Dreamweaver:
- ColdFusion: واجهة مستخدم مجموعة السجلات البسيطة تزيل علامات التجزئة (الهاش) من حول أسماء المتغيرات من استعلام SQL عند تحريرها ثم إعادة تطبيقها
- ColdFusion، ASP_VBS، ASP_JS: لا يعمل زر الاختبار في واجهة مستخدم مجموعة السجلات المتقدمة عندما يحتوي استعلام SQL على أسماء متغيرات
الوصول إلى موقع مجلد تهيئة المستخدم
- نظام التشغيل Windows XP
C:\Documents and Settings\[username]\Application Data\Adobe\Dreamweaver 9\Configuration
- نظام التشغيل Windows Vista
C:\Users\[username]\AppData\Roaming\Adobe\Dreamweaver 9\Configuration
- نظام التشغيل Mac OS 10.4.x
/Users/[username]/Library/Application\ Support/Adobe/Dreamweaver\ 9/Configuration