هل يمكنني الحماية من حقن SQL عن طريق الهروب من علامات الاقتباس المفردة وإدخال المستخدم المحيط بعلامات الاقتباس المفردة؟

StackOverflow https://stackoverflow.com/questions/139199

سؤال

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

sSanitizedInput = "'" & Replace(sInput, "'", "''") & "'"

يتم استبدال أي علامة اقتباس مفردة يدخلها المستخدم بعلامات اقتباس مفردة مزدوجة، مما يلغي قدرة المستخدمين على إنهاء السلسلة، لذا فإن أي شيء آخر قد يكتبونه، مثل الفواصل المنقوطة وعلامات النسبة المئوية وما إلى ذلك، سيكون جميعًا جزءًا من السلسلة وليس يتم تنفيذها فعليًا كجزء من الأمر.نحن نستخدم Microsoft SQL Server 2000، والذي أعتقد أن علامة الاقتباس المفردة هي محدد السلسلة الوحيد والطريقة الوحيدة للهروب من محدد السلسلة، لذلك لا توجد طريقة لتنفيذ أي شيء يكتبه المستخدم.

لا أرى أي طريقة لشن هجوم حقن SQL ضد هذا، لكنني أدرك أنه إذا كان هذا مضادًا للرصاص كما يبدو لي، لكان شخص آخر قد فكر فيه بالفعل وسيكون ممارسة شائعة.سؤالي هو هذا:ما الخطأ في هذا الرمز؟هل يعرف أحد طريقة للحصول على هجوم حقن SQL بعد تقنية التعقيم هذه؟قد يكون نموذج إدخال المستخدم الذي يستغل هذه التقنية مفيدًا للغاية.

تحديث:

شكرا للجميع على إجاباتهم.ظهرت جميع المعلومات التي عثرت عليها في بحثي تقريبًا على هذه الصفحة في مكان ما، وهو ما يدل على ذكاء ومهارة الأشخاص الذين خصصوا وقتًا من أيامهم المزدحمة لمساعدتي في الإجابة على هذا السؤال.

السبب وراء عدم قبولي لأي من الإجابات حتى الآن هو أنني ما زلت لا أعرف أي طريقة لشن هجوم حقن SQL بشكل فعال ضد هذا الرمز.اقترح عدد قليل من الأشخاص أن الشرطة المائلة العكسية ستتجاوز علامة الاقتباس المفردة وتترك الأخرى لإنهاء السلسلة بحيث يتم تنفيذ بقية السلسلة كجزء من أمر SQL، وأدرك أن هذه الطريقة ستعمل على إدخال SQL في قاعدة بيانات MySQL، ولكن في MS SQL 2000 الطريقة الوحيدة (التي تمكنت من العثور عليها) للهروب من علامة الاقتباس المفردة هي باستخدام عرض أسعار مفرد آخر؛الخطوط المائلة العكسية لن تفعل ذلك.وما لم تكن هناك طريقة لوقف هروب علامة الاقتباس المفردة، فلن يتم تنفيذ أي من بقية مدخلات المستخدم لأنه سيتم اعتبارها جميعًا كسلسلة واحدة متجاورة.

أدرك أن هناك طرقًا أفضل لتطهير المدخلات ولكني مهتم جدًا بمعرفة سبب عدم نجاح الطريقة التي قدمتها أعلاه.إذا كان أي شخص يعرف أي طريقة محددة لشن هجوم حقن SQL ضد طريقة التطهير هذه، فأنا أرغب في رؤيتها.

هل كانت مفيدة؟

المحلول

بادئ ذي بدء، إنها مجرد ممارسة سيئة.يعد التحقق من صحة الإدخال ضروريًا دائمًا، ولكنه أيضًا غير ملائم دائمًا.
والأسوأ من ذلك، أن التحقق من صحة القائمة السوداء يمثل دائمًا مشكلة، فمن الأفضل أن تحدد بشكل صريح وصارم القيم/التنسيقات التي تقبلها.من المسلم به أن هذا ليس ممكنًا دائمًا - ولكن إلى حد ما يجب القيام به دائمًا.
بعض الأوراق البحثية حول الموضوع:

النقطة المهمة هي أنه يمكن تجاوز أي قائمة سوداء تقوم بها (والقوائم البيضاء المتساهلة للغاية).يُظهر الرابط الأخير في ورقتي المواقف التي يمكن فيها تجاوز الهروب من الاقتباس.

حتى لو كانت هذه المواقف لا تنطبق عليك، فهي لا تزال فكرة سيئة.علاوة على ذلك، ما لم يكن تطبيقك صغيرًا إلى حد تافه، فسيتعين عليك التعامل مع الصيانة، وربما قدرًا معينًا من الإدارة:كيف يمكنك التأكد من أن الأمر يتم بشكل صحيح، في كل مكان وفي كل وقت؟

الطريقة الصحيحة للقيام بذلك:

  • التحقق من صحة القائمة البيضاء:النوع أو الطول أو التنسيق أو القيم المقبولة
  • إذا كنت تريد إدراجك في القائمة السوداء، فانتقل مباشرةً.يعد الهروب من الاقتباس أمرًا جيدًا، ولكن في سياق عوامل التخفيف الأخرى.
  • استخدم كائنات الأوامر والمعلمات للتحضير والتحقق من الصحة
  • استدعاء الاستعلامات ذات المعلمات فقط.
  • والأفضل من ذلك، استخدام الإجراءات المخزنة حصريًا.
  • تجنب استخدام SQL الديناميكي، ولا تستخدم تسلسل السلسلة لإنشاء الاستعلامات.
  • في حالة استخدام مقدمي الخدمات، يمكنك أيضًا تقييد الأذونات في قاعدة البيانات لتنفيذ مقدمي الخدمات المطلوبين فقط، وعدم الوصول إلى الجداول مباشرة.
  • يمكنك أيضًا التحقق بسهولة من أن قاعدة التعليمات البرمجية بأكملها تصل إلى قاعدة البيانات فقط من خلال مقدمي الخدمة...

نصائح أخرى

حسنًا، سيتعلق هذا الرد بتحديث السؤال:

"إذا كان أي شخص يعرف أي طريقة محددة لشن هجوم حقن SQL ضد طريقة التطهير هذه، فأنا أرغب في رؤيتها."

الآن، بالإضافة إلى هروب الخط المائل العكسي لـ MySQL - ومع الأخذ في الاعتبار أننا نتحدث بالفعل عن MSSQL، هناك في الواقع 3 طرق محتملة لحقن SQL للتعليمات البرمجية الخاصة بك

sSanitizedInput = "'" & استبدال(sInput, "'"، "''") & "'"

ضع في اعتبارك أن هذه العناصر لن تكون كلها صالحة في جميع الأوقات، وتعتمد بشكل كبير على الكود الفعلي الخاص بك حولها:

  1. حقن SQL من الدرجة الثانية - إذا تمت إعادة بناء استعلام SQL بناءً على البيانات المستردة من قاعدة البيانات بعد الهروب, ، تكون البيانات متسلسلة دون هروب وقد يتم حقنها بشكل غير مباشر باستخدام SQL.يرى
  2. اقتطاع السلسلة - (أكثر تعقيدًا بعض الشيء) - السيناريو هو أن يكون لديك حقلين، مثل اسم المستخدم وكلمة المرور، ويقوم SQL بتسلسل كليهما.وكلا الحقلين (أو الأول فقط) لهما حد صارم للطول.على سبيل المثال، يقتصر اسم المستخدم على 20 حرفًا.لنفترض أن لديك هذا الرمز:
username = left(Replace(sInput, "'", "''"), 20)

ثم ما تحصل عليه - هو اسم المستخدم، وتم تهريبه، ثم تقليصه إلى 20 حرفًا.المشكلة هنا - سأضع اقتباسي في الحرف العشرين (على سبيل المثال:بعد 19 حرفًا)، وسيتم قطع اقتباس الهروب الخاص بك (بالحرف الحادي والعشرين).ثم SQL

sSQL = "select * from USERS where username = '" + username + "'  and password = '" + password + "'"

سيؤدي دمج اسم المستخدم المشوه المذكور أعلاه إلى ظهور كلمة المرور بالفعل الخارج علامات الاقتباس، وسوف تحتوي فقط على الحمولة مباشرة.
3.تهريب Unicode - في مواقف معينة، من الممكن تمرير حرف Unicode عالي المستوى تبدو مثل الاقتباس، ولكن ليس كذلك - حتى يصل إلى قاعدة البيانات، حيث فجأة إنها.نظرًا لأنه ليس عرضًا عند التحقق من صحته، فسوف يمر بسهولة ...راجع ردي السابق لمزيد من التفاصيل، واربطه بالبحث الأصلي.

شيء صغير:لا تقم أبدًا بالاستعلام عن الهروب من نفسك.لا بد أن تحصل على شيء خاطئ.بدلاً من ذلك، استخدم الاستعلامات ذات المعلمات، أو إذا لم تتمكن من القيام بذلك لسبب ما، فاستخدم مكتبة موجودة تقوم بذلك نيابةً عنك.ليس هناك سبب للقيام بذلك بنفسك.

أدرك أن هذا قد مر وقت طويل بعد طرح السؤال، ولكن ..

إحدى الطرق لشن هجوم على إجراء "اقتباس الوسيطة" هي اقتطاع السلسلة.وفقًا لـ MSDN، في SQL Server 2000 SP4 (و SQL Server 2005 SP1)، سيتم اقتطاع سلسلة طويلة جدًا بهدوء.

عندما تقتبس سلسلة، يزيد حجم السلسلة.يتم تكرار كل الفاصلة العليا.ويمكن بعد ذلك استخدام هذا لدفع أجزاء من SQL خارج المخزن المؤقت.لذلك يمكنك بشكل فعال قطع أجزاء من جملة أين.

من المحتمل أن يكون هذا مفيدًا في الغالب في سيناريو صفحة "مسؤول المستخدم" حيث يمكنك إساءة استخدام عبارة "التحديث" لعدم إجراء جميع عمليات التحقق التي كان من المفترض إجراؤها.

لذا، إذا قررت اقتباس جميع الوسيطات، فتأكد من أنك تعرف ما يحدث مع أحجام السلسلة وتأكد من عدم تعرضك للاقتطاع.

أوصي بالذهاب مع المعلمات.دائماً.أتمنى فقط أن أتمكن من فرض ذلك في قاعدة البيانات.وكأثر جانبي، من المرجح أن تحصل على نتائج أفضل في ذاكرة التخزين المؤقت لأن المزيد من العبارات تبدو متشابهة.(كان هذا صحيحًا بالتأكيد في Oracle 8)

الصرف الصحي للمدخلات ليس شيئًا تريد نصفه.استخدم مؤخرتك بأكملها.استخدم التعبيرات العادية في حقول النص.حاول إرسال الأرقام الخاصة بك إلى النوع الرقمي الصحيح، وقم بالإبلاغ عن خطأ في التحقق إذا لم ينجح الأمر.من السهل جدًا البحث عن أنماط الهجوم في مدخلاتك، مثل '-.افترض أن جميع المدخلات من المستخدم معادية.

لقد استخدمت هذه التقنية عند التعامل مع وظيفة "البحث المتقدم"، حيث كان إنشاء استعلام من البداية هو الإجابة الوحيدة القابلة للتطبيق.(مثال:السماح للمستخدم بالبحث عن المنتجات بناءً على مجموعة غير محدودة من القيود على سمات المنتج، وعرض الأعمدة وقيمها المسموح بها كعناصر تحكم في واجهة المستخدم الرسومية لتقليل حد التعلم للمستخدمين.)

في حد ذاته فهو آمن AFAIK.كما أشار مجيب آخر، قد تحتاج أيضًا إلى التعامل مع هروب مسافة للخلف (وإن لم يكن ذلك عند تمرير الاستعلام إلى SQL Server باستخدام ADO أو ADO.NET، على الأقل - لا يمكن ضمان جميع قواعد البيانات أو التقنيات).

المشكلة هي أنه عليك أن تكون متأكدًا من السلاسل التي تحتوي على مدخلات المستخدم (التي من المحتمل أن تكون ضارة دائمًا)، وأي السلاسل هي استعلامات SQL صالحة.أحد المصائد هو إذا كنت تستخدم قيمًا من قاعدة البيانات - هل تم توفير هذه القيم في الأصل من قبل المستخدم؟إذا كان الأمر كذلك، فيجب أيضًا الهروب.إجابتي هي محاولة التعقيم في وقت متأخر قدر الإمكان (ولكن ليس لاحقًا!) عند إنشاء استعلام SQL.

ومع ذلك، في معظم الحالات، يعد ربط المعلمات هو الحل الأمثل - فهو أبسط.

إنها فكرة سيئة على أي حال كما يبدو أنك تعلم.

ماذا عن شيء مثل الهروب من الاقتباس في السلسلة مثل هذا:\'

سيؤدي استبدالك إلى:\''

إذا تجاوزت الشرطة المائلة العكسية الاقتباس الأول، فإن الاقتباس الثاني قد أنهى السلسلة.

إجابة بسيطة:وسوف تعمل في بعض الأحيان، ولكن ليس في كل وقت.تريد استخدام التحقق من صحة القائمة البيضاء كل شئ أنت تفعل ذلك، لكنني أدرك أن هذا ليس ممكنًا دائمًا، لذا فأنت مجبر على اختيار القائمة السوداء لأفضل التخمينات.وبالمثل، تريد استخدام procs المخزنة ذات المعلمات في كل شئ, ، ولكن مرة أخرى، هذا ليس ممكنًا دائمًا، لذا فأنت مجبر على استخدام sp_execute مع المعلمات.

هناك طرق للتغلب على أي قائمة سوداء قابلة للاستخدام يمكنك التوصل إليها (وبعض القوائم البيضاء أيضًا).

الكتابة اللائقة هنا: http://www.owasp.org/index.php/Top_10_2007-A2

إذا كنت بحاجة إلى القيام بذلك كحل سريع لإعطائك الوقت للحصول على حل حقيقي، فافعل ذلك.لكن لا تعتقد أنك آمن.

هناك طريقتان للقيام بذلك، بدون استثناءات، لتكون آمنًا من حقن SQL؛بيانات معدة أو إجراءات مخزنة محددة.

إذا كانت لديك استعلامات ذات معلمات متاحة، فيجب عليك استخدامها في جميع الأوقات.كل ما يتطلبه الأمر هو أن يمر استعلام واحد عبر الشبكة وتكون قاعدة البيانات الخاصة بك في خطر.

نعم، يجب أن يعمل هذا حتى يهرب شخص ما قم بإيقاف تشغيل QUOTED_IDENTIFIER ويستخدم اقتباسًا مزدوجًا عليك.

يحرر:الأمر ليس بهذه البساطة مثل عدم السماح للمستخدم الضار بإيقاف تشغيل المعرفات المقتبسة:

يقوم برنامج تشغيل SQL Server Native Client ODBC وSQL Server Native Client OLE DB Provider لـ SQL Server تلقائيًا بتعيين QUOTED_IDENTIFIER على ON عند الاتصال.يمكن تكوين ذلك في مصادر بيانات ODBC، أو في سمات اتصال ODBC، أو خصائص اتصال OLE DB. الإعداد الافتراضي لـ SET QUOTED_IDENTIFIER هو OFF للاتصالات من تطبيقات مكتبة قاعدة البيانات.

عندما يتم إنشاء إجراء مخزن، فإن يتم التقاط إعدادات SET QUOTED_IDENTIFIER وSET ANSI_NULLS واستخدامها للاستدعاءات اللاحقة لهذا الإجراء المخزن.

قم بتعيين QUOTED_IDENTIFIER أيضًا يتوافق مع إعداد QUOTED_IDENTIFER الخاص بـ ALTER DATABASE.

SET QUOTED_IDENTIFIER هو تعيين في وقت التحليل.يعني الإعداد في وقت التحليل أنه إذا كانت عبارة SET موجودة في الدفعة أو الإجراء المخزن، فإنها تصبح سارية المفعول، بغض النظر عما إذا كان تنفيذ التعليمات البرمجية يصل بالفعل إلى تلك النقطة؛وتصبح عبارة SET نافذة المفعول قبل تنفيذ أية عبارات.

هناك العديد من الطرق التي يمكن من خلالها إيقاف تشغيل QUOTED_IDENTIFIER دون أن تعرف ذلك بالضرورة.من المسلم به أن هذا ليس هو الاستغلال الدامغ الذي تبحث عنه، ولكنه سطح هجوم كبير جدًا.بالطبع، إذا هربت أيضًا من علامات الاقتباس المزدوجة، فسنعود إلى حيث بدأنا.;)

دفاعك سيفشل إذا:

  • يتوقع الاستعلام رقمًا وليس سلسلة
  • كانت هناك أي طريقة أخرى لتمثيل علامة الاقتباس المفردة، بما في ذلك:
    • تسلسل الهروب مثل \039
    • حرف يونيكود

(في الحالة الأخيرة، يجب أن يكون شيئًا تم توسيعه فقط بعد الانتهاء من الاستبدال)

باتريك، هل تضيف علامات اقتباس مفردة حول جميع المدخلات، حتى المدخلات الرقمية؟إذا كان لديك مدخلات رقمية، ولكنك لا تضع علامات الاقتباس المفردة حولها، فهذا يعني أن لديك تعريضًا.

يا له من رمز قبيح سيكون كل هذا التطهير لمدخلات المستخدم!ثم StringBuilder عالي الكعب لبيان SQL.تؤدي طريقة البيان المجهزة إلى تعليمات برمجية أكثر وضوحًا، كما أن فوائد حقن SQL هي إضافة رائعة حقًا.

وأيضا لماذا إعادة اختراع العجلة؟

بدلاً من تغيير الاقتباس الفردي (على ما يبدو) إلى اقتباسين منفردين، لماذا لا نغيره إلى فاصلة عليا، أو اقتباس، أو نزيله بالكامل؟

على أية حال، الأمر فيه نوع من الحماقة..خاصة عندما يكون لديك أشياء (مثل الأسماء) بشكل شرعي والتي قد تستخدم علامات الاقتباس المفردة ...

ملحوظة:تفترض طريقتك أيضًا أن كل من يعمل على تطبيقك يتذكر دائمًا تنظيف المدخلات قبل أن تصل إلى قاعدة البيانات، وهو الأمر الذي ربما لا يكون واقعيًا في معظم الأوقات.

على الرغم من أنك قد تجد حلاً مناسبًا للسلاسل، إلا أنه بالنسبة للمسندات الرقمية، تحتاج أيضًا إلى التأكد من أنها تمرر أرقامًا فقط (الفحص البسيط هو هل يمكن تحليلها كـ int/double/decimal؟).

إنه الكثير من العمل الإضافي.

قد ينجح الأمر، لكنه يبدو مربكًا بعض الشيء بالنسبة لي.أوصي بالتحقق من صحة كل سلسلة عن طريق اختبارها مقابل تعبير عادي بدلاً من ذلك.

نعم يمكنك ذلك إذا...

بعد دراسة الموضوع، أعتقد أن المدخلات المنقحة كما اقترحت آمنة، ولكن فقط بموجب هذه القواعد:

  1. لا تسمح أبدًا لقيم السلسلة الواردة من المستخدمين بأن تصبح أي شيء آخر غير سلسلة حرفية (أي.تجنب إعطاء خيار التكوين:"أدخل أسماء/تعبيرات أعمدة SQL إضافية هنا:").أنواع القيم بخلاف السلاسل (الأرقام، التواريخ، ...):قم بتحويلها إلى أنواع البيانات الأصلية الخاصة بها وتوفير روتين لـ SQL الحرفي من كل نوع بيانات.

    • تعتبر عبارات SQL مشكلة في التحقق من صحتها
  2. إما أن تستخدم nvarchar/nchar الأعمدة (والسلسلة الحرفية البادئة مع N) أو الحد من القيم التي تدخل varchar/char الأعمدة إلى أحرف ASCII فقط (على سبيل المثال.رمي الاستثناء عند إنشاء عبارة SQL)

    • بهذه الطريقة ستتجنب التحويل التلقائي للفاصلة العليا من CHAR(700) إلى CHAR(39) (وربما عمليات اختراق Unicode مماثلة أخرى)
  3. يمكنك دائمًا التحقق من صحة طول القيمة لتناسب طول العمود الفعلي (رمي الاستثناء إذا كان أطول)

    • كان هناك عيب معروف في SQL Server يسمح بتجاوز خطأ SQL الذي تم طرحه عند الاقتطاع (مما يؤدي إلى الاقتطاع الصامت)
  4. أنت تضمن ذلك SET QUOTED_IDENTIFIER دائما ON

    • احذر، فهو يدخل حيز التنفيذ في وقت التحليل، أي.حتى في أقسام التعليمات البرمجية التي يتعذر الوصول إليها

بالامتثال لهذه النقاط الأربع، يجب أن تكون آمنًا.إذا قمت بانتهاك أي منها، فسيتم فتح طريقة لحقن SQL.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top