في هذا القسم، سنشرح ماهية حقن SQL (SQL injection)، ونذكر بعض الأمثلة الشائعة، ونشرح كيفية العثور على أنواع مختلفة من ثغرات حقن الـ SQL واستغلالها، ونلخص كيفية منع حقن الـ SQL.
ما هو حقن الـ SQL أو (SQLi)؟
حقن الـ SQL عبارة عن ثغرة أمنية على الويب تسمح للمهاجمين بالتنصت (interfere بالتداخل) على الاستعلامات التي يرسلها أحد التطبيقات إلى قاعدة البيانات الخاصة به. ما يسمح في معظم الأحيان للمهاجمين بالاطلاع على البيانات التي لا يستطيعون الحصول عليها عادةً. قد يشمل ذلك البيانات الخاصة بمستخدمين آخرين، أو أي بيانات أخرى يستطيع التطبيق نفسه الوصول إليها. في كثير من الحالات، يمكن للمهاجم تعديل أو حذف هذه البيانات، مما يؤدي إلى تغييرات دائمة في محتوى أو سلوك التطبيق.
في بعض الحالات، يمكن للمهاجم توسيع هجوم حقن الـ SQL لخرق الخادم الأساسي أو البنية الأساسية الخلفية الأخرى، أو تنفيذ هجوم رفض الخدمة (denial-of-attack).

ما هو تأثير هجوم حقن الـ SQL الناجح؟
يمكن أن يؤدي هجوم حقن الـ SQL الناجح إلى الوصول غير المسموح به إلى البيانات الحساسة، مثل كلمات المرور أو تفاصيل بطاقة الائتمان أو معلومات المستخدم الشخصية. العديد من خروقات البيانات البارزة في السنوات الأخيرة كانت نتيجة هجمات حقن الـ SQL ، مسببةً أضراراً في السمعة وغرامات تنظيمية. وفي بعض الحالات، يمكن للمهاجم الحصول على باب خلفي (backdoor) دائم في أنظمة المؤسسة، مما يؤدي إلى إخضاعٍ طويل الأجل (لتلك الأنظمة) يمكن أن يمر دون أن يلاحظه أحد لفترة طويلة.
أمثلة حقن SQL:
هناك مجموعة واسعة من ثغرات وهجمات، وتقنيات حقن الـ SQL ، والتي تنشأ في حالات مختلفة. تتضمن بعض أمثلة حقن الـ SQL الشائعة:
- استرداد البيانات المخفية ، حيث يمكنك تعديل استعلام SQL لإرجاع نتائج إضافية.
- تخريب منطق (logic) التطبيق ، حيث يمكنك تغيير الاستعلام ليتضارب مع منطق التطبيق.
- هجمات UNION ، حيث يمكنك استرداد البيانات من جداول قاعدة البيانات المختلفة.
- فحص قاعدة البيانات ، حيث يمكنك استخراج معلومات حول إصدار وهيكلية قاعدة البيانات.
- هجمات حقن SQL العمياء (Blind SQL injection)، حيث لا يتم إرجاع نتائج الاستعلام الذي تتحكم فيه ضمن استجابات (responses) التطبيق.
استعادة البيانات المخفية:
بفرض حالة تطبيق تسوق يعرض المنتجات في فئات مختلفة. عندما ينقر المستخدم على فئة الهدايا، يطلب متصفح الخاص به عنوان الـ URL التالي:
https://insecure-website.com/products?category=Gifts
يؤدي هذا إلى جعل التطبيق يقوم بإجراء استعلام SQL للحصول على تفاصيل المنتجات ذات الصلة من قاعدة البيانات:
SELECT * FROM products WHERE category = 'Gifts' AND released = 1
يطلب استعلام SQL هذا من قاعدة البيانات إرجاع:
- كل التفاصيل (*)
- من جدول المنتجات (products)
- حيث الفئة (category) هي الهدايا (Gifts)
- و released (اسم لأحد الحقول الموجودة في قاعدة البيانات -المترجم-) يساوي 1.
حيث تم استخدام التقييد released = 1 لإخفاء المنتجات التي لم يتم إصدارها. أما بالنسبة للمنتجات التي لم يتم إصدارها بعد ، فيُفترض أنها released = 0.
لا ينفذ التطبيق أي دفاعات ضد هجمات حقن الـ SQL ، لذلك يمكن للمهاجم إنشاء هجوم مثل:
https://insecure-website.com/products?category=Gifts'--
ينتج عن هذا استعلام SQL:
SELECT * FROM products WHERE category = 'Gifts'--' AND released = 1
الشيء الرئيسي هنا هو أن تسلسل شرطة مزدوجة (–) هو مؤشر تعليق (comment) في SQL ، ويعني أن بقية الاستعلام يتم تفسيره على أنه تعليق. يؤدي هذا بالفعل إلى إزالة ما تبقى من الاستعلام، وبالتالي لم يعد يتضمن AND released = 1 . وهذا يعني أن جميع المنتجات سيتم عرضها، بما في ذلك المنتجات غير المُصدرة.
وأكثر من ذلك، قد يتسبب المهاجم في جعل التطبيق يقوم بعرض جميع المنتجات في أي فئة، بما في ذلك الفئات التي لا يعرفون عنها :
https://insecure-website.com/products?category=Gifts'+OR+1=1--
ينتج عن هذا استعلام SQL:
SELECT * FROM products WHERE category = 'Gifts' OR 1=1--' AND released = 1
سيُرجع الاستعلام المعدل كل العناصر حيث : تكون فيها الفئة هي Gifts (هدايا) ، أو 1 تساوي 1. وطالما أن 1 = 1 صحيح دائما ، سيُعيد الاستعلام جميع العناصر.
تخريب منطق التطبيق:
في حالة تطبيق يتيح للمستخدمين تسجيل الدخول بواسطة اسم المستخدم و كلمة المرور. إذا أرسل أحد المستخدمين اسم المستخدم wiener وكلمة المرور bluecheese ، يتحقق التطبيق من البيانات الشخصية (credentials أو بيانات الاعتماد) عن طريق إجراء استعلام SQL التالي:
SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese
إذا أرجع الاستعلام التفاصيل الخاصة بالمستخدم، فسيتم تسجيل الدخول بنجاح. خلاف ذلك، يتم رفضه.
هنا، يمكن للمهاجم تسجيل الدخول كأي مستخدم دون كلمة مرور ببساطة باستخدام سلسلة تعليق SQL (–) لإزالة التحقق من كلمة المرور من عبارة WHERE ضمن الاستعلام. على سبيل المثال، إرسال اسم المستخدم administrator’– وكلمة مرور فارغة ينتج الاستعلام التالي:
SELECT * FROM users WHERE username = 'administrator'--' AND password = ''
يقوم هذا الاستعلام بإرجاع المستخدم صاحب اسم المستخدم administrator ويقوم بتسجيل دخول المهاجم بنجاح على أنه ذلك المستخدم.
استرداد البيانات من الجداول الأخرى لقاعدة البيانات:
في الحالات التي يتم فيها إرجاع نتائج استعلام SQL ضمن استجابات التطبيق، يمكن للمهاجم الاستفادة من ثغرة حقن الـ SQL لاسترداد البيانات من الجداول الأخرى داخل قاعدة البيانات. يتم ذلك باستخدام الكلمة الأساسية UNION ، التي تتيح لك تنفيذ استعلام SELECT إضافي وإلحاق النتائج بالاستعلام الأصلي.
على سبيل المثال، إذا نفذ أحد التطبيقات الاستعلام التالي الذي يحتوي على إدخال من المستخدم هو “Gifts”:
SELECT name, description FROM products WHERE category = 'Gifts'
يمكن للمهاجم إرسال الإدخال:
' UNION SELECT username, password FROM users--
سيؤدي ذلك إلى قيام التطبيق بإرجاع جميع أسماء المستخدمين وكلمات المرور مع أسماء المنتجات ووصفها.
فحص قاعدة البيانات:
بعد التعرف المبدئي على ثغرة حقن الـ SQL ، من المفيد عموماً معرفة بعض المعلومات عن قاعدة البيانات نفسها. وغالباً ما تمهد هذه المعلومات الطريق لمزيد من الاستغلال.
يمكنك الاستعلام عن تفاصيل إصدار (version) قاعدة البيانات. تعتمد الطريقة التي يتم بها ذلك على نوع قاعدة البيانات، وبالتالي يمكنك استنتاج نوع قاعدة البيانات من أي أسلوب يفي بالغرض. على سبيل المثال، في Oracle يمكنك تنفيذ:
SELECT * FROM v$version
يمكنك أيضاً تحديد جداول قواعد البيانات الموجودة والأعمدة التي تحتوي عليها. على سبيل المثال، في معظم قواعد البيانات، يمكنك تنفيذ الاستعلام التالي لسرد الجداول:
SELECT * FROM information_schema.tables
ثغرات حقن الـ SQL العمياء:
العديد من نُسَخ (أو حالات -المترجم-) حقن الـ SQL هي ثغرات عمياء. هذا يعني أن التطبيق لا يُرجع نتائج استعلام SQL أو تفاصيل أي أخطاء في قاعدة البيانات ضمن استجاباته (responses). إلا أنه لا يزال من الممكن استغلال نقاط الضعف العمياء للوصول إلى البيانات غير المصرح (أو المسموح) بها، ولكن التقنيات المستخدمة تكون عموماً أكثر تعقيداً ومن الصعب تنفيذها.
اعتماداً على طبيعة الثغرة وقاعدة البيانات المعنية، يمكن استخدام التقنيات التالية لاستغلال ثغرات حقن الـ SQL العمياء:
- يمكنك تغيير منطق (logic) الاستعلام لإحداث اختلاف يمكن اكتشافه في استجابة التطبيق تبعاً لتحقق شرط وحيد. قد يتضمن ذلك حقن شرط جديد ضمن منطق من نوع Boolean، أو إحداثُ خطأٍ مشروط مثل القسمة على الصفر.
- يمكنك إحداث تأخير زمني مشروط في معالجة الاستعلام، مما يسمح لك باستنتاج تحقق الشرط بناءً على الوقت الذي يستغرقه التطبيق للاستجابة.
- يمكنك إحداث تبادل شبكي خارج النطاق (out-of-band) ، باستخدام تقنيات OAST. هذه التقنية قوية للغاية وتعمل في الحالات التي لا تعمل فيها التقنيات الأخرى. في كثير من الأحيان، يمكنك تهريب البيانات مباشرة عبر قناة (channel) خارج النطاق، على سبيل المثال عن طريق وضع البيانات في بحث DNS لنطاق تتحكم فيه.
كيفية اكتشاف ثغرات حقن SQL:
يمكن العثور على معظم ثغرات حقن الـ SQL بسرعة وبشكل موثوق باستخدام Burp Suite’s web vulnerability scanner (فاحص ثغرات الوب لحزمة Burp Suite) .
يمكن اكتشاف حقن الـ SQL يدوياً باستخدام مجموعة منهجية من الاختبارات مقابل كل نقطة إدخال (entry point) في التطبيق. يتضمن هذا عادة:
- تقديم حرف الاقتباس الأحادي (‘) والبحث عن الأخطاء أو غيرها من الحالات الشاذة.
- إرسال بعض العبارات الخاصة بـ SQL التي يمكن أن يتم تقييمها إلى القيمة الأساسية (الأصلية) لنقطة الإدخال، و إلى قيمة مختلفة، والبحث عن الاختلافات المنهجية في استجابات التطبيق الناتجة.
- تقديم الشروط المنطقية مثل OR 1 = 1 و OR 1 = 2 ، والبحث عن الاختلافات في استجابات التطبيق.
- تقديم حمولات (payloads) مصممة لإحداث تأخير زمني عند تنفيذها ضمن استعلام SQL ، والبحث عن الاختلافات في الوقت المستغرق للاستجابة.
- إرسال حمولات OAST مصممة لإحداث تبادل شبكي خارج النطاق عند تنفيذها داخل استعلام SQL ، ومراقبة أي تبادلات ناتجة.
حقن SQL في أجزاء مختلفة من الاستعلام :
تنشأ معظم ثغرات حقن الـ SQL ضمن جملة WHERE من استعلام SELECT. هذا النوع من حقن الـ SQL مفهوم بشكل جيد عموماً للمختبرين (testers) ذوي الخبرة.
ولكن يمكن أن تحدث ثغرات حقن الـ SQL – من حيث المبدأ – في أي مكان ضمن الاستعلام، وضمن أنواع الاستعلام المختلفة. المواقع الأخرى الأكثر شيوعاً التي ينشأ فيها حقن الـ SQL هي:
- في عبارات UPDATE ، ضمن القيم المحدّثة أو جملة WHERE.
- في عبارات INSERT ، ضمن القيم المدرجة (التي يتم إدخالها إلى قاعدة اليبانات).
- في عبارات SELECT ، ضمن اسم الجدول أو اسم العمود.
- في عبارات SELECT ، ضمن جملة ORDER BY.
حقن الـ SQL في الطلب الثاني (Second-order):
ينشأ حقن الـ SQL في الطلب الأول First-order عندما يأخذ التطبيق إدخال (input) المستخدم من طلب HTTP، وفي سياق معالجة هذا الطلب، يدمج الإدخال في استعلام SQL بطريقة غير آمنة.
في حالة حقن الـ SQL في الطلب الثاني Second-order (المعروف أيضاً باسم حقن الـ SQL المُخَزَّن stored SQL injection)، يأخذ التطبيق إدخال المستخدم من طلب HTTP ويخزنه ليستخدمه في المستقبل. يتم ذلك عادةً عن طريق وضع الإدخال في قاعدة بيانات، إلا أنه لا تنشأ ثغرة أمنية عند نقطة التي يتم فيها تخزين البيانات. في وقت لاحق، عند معالجة طلب HTTP مختلف، يسترجع التطبيق البيانات المخزنة ويدمجها في استعلام SQL بطريقة غير آمنة.

غالباً ما ينشأ حقن الـ SQL في الطلب الثاني في الحالات التي يكون فيها المطورون على دراية بثغرات حقن الـ SQL ، فيعالجون الإدخال الأولي (أو المبدئي initial) للمدخلات (input) في قاعدة البيانات بشكل آمن. وعندما تتم معالجة البيانات لاحقاً، يتم اعتبارها آمنة، حيث تم وضعها مسبقاً بأمان في قاعدة البيانات. وعند هذه النقطة، يتم التعامل مع البيانات بطريقة غير آمنة، لأن المطور يعتبرها خطأً بأنها موثوقة.
العوامل الخاصة بقاعدة البيانات:
يتم تطبيق بعض الميزات الأساسية للغة SQL بنفس الطريقة عبر منصات قواعد البيانات الشائعة، ولذلك فالعديد من طرق اكتشاف واستغلال ثغرات حقن الـ SQL تعمل بنفس الأسلوب على أنواع مختلفة من قاعدة البيانات.
ومع ذلك، هناك أيضاً العديد من الاختلافات بين قواعد البيانات الشائعة. وهذا يعني أن بعض التقنيات لاكتشاف واستغلال حقن الـ SQL تعمل بشكل مختلف على منصات مختلفة. فعلى سبيل المثال :
- طريقة كتابة (أو أسلوب كتابة Syntax) ربط السلاسل (string concatenation).
- التعليقات (Comments).
- الاستعلامات المجمعة (أو المكدسة) [Batched (or stacked) queries].
- واجهات برمجة التطبيقات (APIs) الخاصة بالنظام (أو المنصة platform).
- رسائل الخطأ (error messages).
إقرأ المزيد:
ورقة الغش (cheat sheet) لحقن الـ SQL
كيفية منع حقن SQL:
يمكن منع معظم حالات حقن الـ SQL من خلال استخدام استعلامات بوسطاء parameters (تُعرف أيضاً باسم العبارات المُعَدَّة prepared statements) بدلاً من ربط السلاسل (string concatenation) ضمن الاستعلام.
التعليمات البرمجية (الكود) التالية عرضة لحقن الـ SQL لأن إدخال (input) المستخدم يتم ربطه (concatentated) مباشرة ضمن الاستعلام:
String query = "SELECT * FROM products WHERE category = '"+ input + "'";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query);
يمكن إعادة كتابة هذا الكود بسهولة بطريقة تمنع التداخل بين المدخلات (inputs) الخاصة بالمستخدم مع بنية الاستعلام:
PreparedStatement statement = connection.prepareStatement("SELECT * FROM products WHERE category = ?");
statement.setString(1, input);
ResultSet resultSet = statement.executeQuery();
يمكن استخدام الاستعلامات ذات الوسطاء (parameterized queries) في أي حالة يظهر فيها إدخال غير موثوق به كبيانات ضمن الاستعلام، بما في ذلك جملة WHERE والقيم (values) في عبارة INSERT أو UPDATE. ولا يمكن استخدامها للتعامل مع المدخلات غير الموثوق بها في أجزاء أخرى من الاستعلام، مثل أسماء الجداول أو الأعمدة أو جملة ORDER BY. ستحتاج وظيفة (functionality أو إجرائية) التطبيق التي تضع بيانات غير موثوقة في تلك الأجزاء من الاستعلام إلى اتباع نهج مختلف، مثل إدخال القيم المسموح بها ضمن القائمة البيضاء (white-list) أو استخدام منطق (logic أو أسلوب عمل) مختلف لإعطاء السلوك المطلوب.
لكي يكون الاستعلام ذو الوسطاء فعالاً في منع حقن الـ SQL، يجب أن تكون السلسلة المستخدمة في الاستعلام دائماً ثابتة ويتم إدخالها مباشرة ضمن الكود (hard coded)، ويجب ألا تحتوي أبداً على أي بيانات لمتغيرات من أي مصدر. لا تنخدع (أو تُغرى[يتم إغراؤك] be tempted) بأن تقرر ما إذا كان عنصر البيانات موثوقاً به حالة بحالة (case-by-case) ، وتستمر في استخدام ربط السلاسل (string concatenation) ضمن الاستعلام للحالات التي تعتبر آمنة. فمن السهل جداً ارتكاب أخطاء حول المصدر (أو الأصل) المحتمل للبيانات، أو عن التغييرات في التعليمات البرمجية الأخرى لانتهاك (violate وهنا بمعنى الاستغلال الاحتيالي) الافتراضات حول البيانات الملوثة (tainted أو التي يمكن من خلالها حقن الـ SQL).