سؤال

إذا كان لي أن اختيار صف من الجدول أنا في الأساس لديها خياران ، إما مثل هذا

int key = some_number_derived_from_a_dropdown_or_whatever
SqlCommand cmd = new SqlCommand("select * from table where primary_key = " + key.ToString());

أو استخدام المعلمة

SqlCommand cmd = new SqlCommand("select * from table where primary_key = @pk");
SqlParameter param  = new SqlParameter();
param.ParameterName = "@pk";
param.Value         = some_number_derived_from_a_dropdown_or_whatever;
cmd.Parameters.Add(param);

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

سؤالي هو:هل استخدام الخيار 1 في رمز الإنتاج لأنك تنظر في استخدام آمن بسبب سهولة الاستخدام والتحكم إدراج المعلمة (مثل ما ورد أعلاه ، أو إذا كانت المعلمة يتم إنشاؤه في التعليمات البرمجية)?أو هل استخدام المعلمات بغض النظر عن ماذا ؟ معلمات 100% حقن آمنة ؟

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

المحلول

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

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

الآن أين المعلمات فرقا هو أن العميل الذي يرسل استعلام مثل select * from table where primary_key = @pk سوف ترسل بالضبط نفس نص SQL في كل مرة بغض النظر عن قيمة مهتمة في.ما يحدث بعد ذلك هو أن كامل عملية وصفت أعلاه هو تماس.SQL سيتم البحث في الذاكرة خطة تنفيذ الخام ، unparsed, النص انها تلقت (على أساس تجزئة هضم المدخلات) ، إذا وجدت ، سيتم تنفيذ هذه الخطة.هذا يعني أن أي تحليل لا التحسين لا شيء دفعة يذهب مباشرة إلى التنفيذ.على OLTP أنظمة تشغيل مئات الآلاف من الطلبات الصغيرة في كل ثانية ، وهذا المسار السريع يجعل ضخمة الفارق في الأداء.

إذا قمت بإرسال استفسار في شكل select * from table where primary_key = 1 ثم SQL على الأقل تحليل ذلك إلى فهم ما هو داخل النص لأن النص هو على الأرجح واحدة جديدة مختلفة عن السابقة أي دفعة فإنه ينظر (حتى حرف واحد مثل 1 مقابل 2 يجعل كل دفعة مختلفة).ثم سوف تعمل على إلى شجرة جملة و محاولة عملية تسمى بسيطة Parameterisation.إذا كان الاستعلام يمكن أن تكون السيارات-paremeterized ، ثم SQL المرجح أن تجد مؤقتا تنفيذ خطة من الاستفسارات التي تعمل سابقا مع pk القيم وإعادة استخدام تلك الخطة ، لذلك على الأقل الاستعلام الخاص بك لا تحتاج إلى أن يكون الأمثل و يمكنك تخطي الخطوة توليد التنفيذ الفعلي للخطة.ولكن لا يعني هل تحقيق كامل ماس كهربائى ، أقصر وقت ممكن مسار تحقيق الحقيقية مع العميل استعلام معلمات.

يمكنك أن تبحث في SQL Server, SQL الإحصاءات كائن عداد الأداء من الخادم الخاص بك.العداد Auto-Param Attempts/sec سوف تظهر عدة مرات في الثانية SQL يجب أن تترجم استعلام تلقى دون المعلمات في السيارات-معلمات واحد.كل محاولة يمكن تجنبها إذا كنت بشكل صحيح parameterize الاستعلام في العميل.إذا كان لديك أيضا عدد كبير من Failed Auto-Params/sec هو أسوأ من ذلك ، فهذا يعني الاستعلامات تسير دورة كاملة من التحسين و تنفيذ خطة جيل.

نصائح أخرى

دائما استخدام الخيار 2).

أول واحد هو لا آمنة فيما يتعلق هجمات حقن SQL.

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

لماذا يجب عليك تجنب الخيار 1

وعلى الرغم من أنه يبدو أنك تحصل على هذه القيمة من عنصر select، قد شخص وهمية طلب HTTP وآخر ما يريدون داخل حقول معينة. التعليمات البرمجية في الخيار 1 يجب أن يحل محل ما لا يقل عن بعض الشخصيات الخطيرة / مجموعات (أي علامات الاقتباس المفردة، بين قوسين معقوفين الخ.).

لماذا أنت تشجع على استخدام الخيار 2

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

وأنا لم أسمع من أي سبيل المثال حيث المعلمات يمكن مخطوفة لحقن SQL. حتى أرى أنه يثبت العكس، كنت تنظر بها وآمنة.

لا ينبغي أبدا أن يعتبر

والحيوي SQL آمنة. حتى مع إدخال "ثقة"، انها عادة سيئة للوصول الى. لاحظ أن هذا يتضمن SQL حيوية في الإجراءات المخزنة. يمكن أن يحدث حقن SQL هناك أيضا.

لأن لديك السيطرة أن القيمة عدد صحيح ، فهي كثيرا ما يعادلها.عموما أنا لا تستخدم النموذج الأول, و عادة لا تسمح الثاني إما لأنني عادة لا تسمح الجدول وتحتاج إلى استخدام الإجراءات المخزنة.وعلى الرغم من أنك يمكن أن تفعل SP التنفيذ دون استخدام معلمات جمع ما زلت أوصي باستخدام SPs و المعلمات:

-- Not vulnerable to injection as long as you trust int and int.ToString()
int key = some_number_derived_from_a_dropdown_or_whatever ;
SqlCommand cmd = new SqlCommand("EXEC sp_to_retrieve_row " + key.ToString()); 

-- Vulnerable to injection all of a sudden
string key = some_number_derived_from_a_dropdown_or_whatever ;
SqlCommand cmd = new SqlCommand("EXEC sp_to_retrieve_row " + key.ToString()); 

لاحظ أنه على الرغم من أن الخيار 1 هو آمن في حالتك, ماذا يحدث عندما يرى شخص ما يستخدم هذا الأسلوب مع غير متغير عدد صحيح - أنت الآن تدريب الناس على استخدام الأسلوب الذي يمكن أن يكون فتح الحقن.

لاحظ أنه يمكنك بشكل استباقي هاردن قاعدة البيانات الخاصة بك لتجنب الحقن فعالة حتى عندما الخاص بك رمز التطبيق الخاطئ.الحسابات/الأدوار التي تستخدم التطبيقات:

  • فقط تسمح بالوصول إلى الجداول كما ضروري
  • فقط تسمح بالوصول إلى وجهات النظر من الضروري على الاطلاق
  • لا تسمح البيانات DDL
  • يسمح تنفيذ تدابير الصحة والصحة النباتية على دور أساس
  • أي ديناميكية SQL في SPs وينبغي النظر ضروري

وأنا شخصيا دائما استخدام الخيار 2 على سبيل العادة. أن يقال:

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

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