मापदंडों के बिना SQL इंजेक्शन से बचना


109

हम अपने कोड में पैराट्राइज्ड एसक्यूएल प्रश्नों का उपयोग करने के बारे में यहां एक और चर्चा कर रहे हैं। चर्चा में हमारे दो पक्ष हैं: मुझे और कुछ अन्य लोगों का कहना है कि हमें हमेशा sql इंजेक्शन से बचाव के लिए मापदंडों का उपयोग करना चाहिए और अन्य लोग जो यह नहीं सोचते कि यह आवश्यक है। इसके बजाय वे एसक्यूएल इंजेक्शन से बचने के लिए सभी तारों में दो एपोस्ट्रोफ के साथ एकल एपोस्ट्रोफ को बदलना चाहते हैं। हमारे डेटाबेस सभी Sql सर्वर 2005 या 2008 में चल रहे हैं और हमारा कोड आधार .NET फ्रेमवर्क 2.0 पर चल रहा है।

मैं आपको C # में एक सरल उदाहरण देता हूं:

मैं चाहता हूं कि हम इसका उपयोग करें:

string sql = "SELECT * FROM Users WHERE Name=@name";
SqlCommand getUser = new SqlCommand(sql, connection);
getUser.Parameters.AddWithValue("@name", userName);
//... blabla - do something here, this is safe

जबकि अन्य लोग ऐसा करना चाहते हैं:

string sql = "SELECT * FROM Users WHERE Name=" + SafeDBString(name);
SqlCommand getUser = new SqlCommand(sql, connection);
//... blabla - are we safe now?

जहां SafeDBString फ़ंक्शन को निम्नानुसार परिभाषित किया गया है:

string SafeDBString(string inputValue) 
{
    return "'" + inputValue.Replace("'", "''") + "'";
}

अब, जब तक हम अपने प्रश्नों में सभी स्ट्रिंग मानों पर SafeDBString का उपयोग करते हैं, तब तक हमें सुरक्षित होना चाहिए। सही?

SafeDBString फ़ंक्शन का उपयोग करने के दो कारण हैं। पहला, यह वह तरीका है जो पत्थर की उम्र के बाद से किया गया है, और दूसरा, sql वक्तव्यों को डीबग करना आसान है क्योंकि आप डेटाबेस पर चलाई गई एक्सक्लूसिव क्वेरी को देखते हैं।

तो फिर। मेरा सवाल यह है कि क्या यह वास्तव में एसक्यूएल इंजेक्शन के हमलों से बचने के लिए सेफडबीएसट्रिंग फ़ंक्शन का उपयोग करने के लिए पर्याप्त है। मैं कोड के उदाहरण खोजने की कोशिश कर रहा हूं जो इस सुरक्षा उपाय को तोड़ता है, लेकिन मुझे इसका कोई उदाहरण नहीं मिल रहा है।

क्या कोई ऐसा व्यक्ति है जो इसे तोड़ सकता है? आपको इसे कैसे करना होगा?

संपादित करें: अब तक के उत्तरों को संक्षेप में प्रस्तुत करने के लिए:

  • किसी को अभी तक Sql Server 2005 या 2008 पर SafeDBString के आसपास जाने का कोई रास्ता नहीं मिला है। यह अच्छा है, मुझे लगता है?
  • कई उत्तरों ने बताया कि पैरामीट्रिक प्रश्नों का उपयोग करने पर आपको प्रदर्शन लाभ मिलता है। कारण यह है कि क्वेरी योजनाओं का पुन: उपयोग किया जा सकता है।
  • हम यह भी मानते हैं कि पैराड्राइज्ड प्रश्नों का उपयोग करने से अधिक पठनीय कोड मिलता है जिसे बनाए रखना आसान होता है
  • इसके अलावा सेफगबीएसट्रिंग के विभिन्न संस्करणों, स्ट्रिंग से नंबर रूपांतरण और स्ट्रिंग से डेट टू डेट का उपयोग करने की तुलना में पैरामीटर का उपयोग करना हमेशा आसान होता है।
  • मापदंडों का उपयोग करके आप स्वचालित प्रकार का रूपांतरण प्राप्त करते हैं, कुछ ऐसा जो विशेष रूप से तब उपयोगी होता है जब हम तिथियों या दशमलव संख्याओं के साथ काम कर रहे होते हैं।
  • और अंत में: अपने आप को सुरक्षा करने की कोशिश मत करो जैसा कि जूलियनआर ने लिखा था। डेटाबेस विक्रेता सुरक्षा पर बहुत समय और पैसा खर्च करते हैं। कोई ऐसा तरीका नहीं है जिससे हम बेहतर कर सकें और कोई कारण नहीं कि हमें उनका काम करने की कोशिश करनी चाहिए।

इसलिए जब कोई भी SafeDBString फ़ंक्शन की सरल सुरक्षा को तोड़ने में सक्षम नहीं था, तो मुझे बहुत सारे अन्य अच्छे तर्क मिले। धन्यवाद!


16
आपके सहकर्मियों का तरीका, तरीका, ऑफ बेस है। उनकी स्थिति के समर्थन में साहित्य का एक टुकड़ा खोजने के लिए उन्हें चुनौती दें। तर्क पूर्व निओलिथोस हास्यास्पद है, चीजें बदल जाती हैं, केवल पत्थर की उम्र में फंसे व्यक्ति को अनुकूलित करने में विफल होगा।
अन्नकूट

1
ठीक है, कम से कम आपके सहकर्मी हैक के विभिन्न रूपों में से एक के खिलाफ की रक्षा करते हैं ... क्या वे सुनिश्चित हैं कि सभी पैरामीटरयुक्त प्रश्न हैं? (मैं नहीं हूँ ...)
अर्जन ईनबू

1
कोई भी भेद्यता उन्हें मना नहीं करेगी। यदि आप कई कमजोरियां लाते हैं (जो आप पूछ रहे हैं) और अन्य मुद्दे और एक-एक करके इंगित करते हैं कि पैरामीटर उस मुद्दे को हल करेंगे और आपकी टीम को कार्यक्षमता का एक अंश प्रदान करने के लिए कोड के पहाड़ों को लिखना होगा, तो आप हो सकते हैं उन्हें जीतना। सौभाग्य।
रॉबर्ट गौलैंड

3
एकल उद्धरणों के बिना भी, आप अभी भी तर्क के साथ अपना कोड तोड़ सकते हैं। उपयोगकर्ता नाम "परीक्षण या 1 = 1" का उपयोग करने का प्रयास करें - आपको उपयोगकर्ता नाम परीक्षण के साथ केवल एक के बजाय सभी पंक्तियाँ वापस मिल जाती हैं!
पुल

1
आह। मैं वास्तव में नहीं मिलता है कि कैसे हम एक उद्योग के रूप में इस तरह के अव्यवसायिक व्यवहार को सहन करने का प्रबंधन करते हैं।
jeroenh

जवाबों:


83

मुझे लगता है कि सही उत्तर है:

अपने आप को सुरक्षा करने की कोशिश मत करो । का प्रयोग करें जो कुछ भी भरोसा किया, उद्योग मानक पुस्तकालय वहाँ तुम क्या करने की कोशिश कर रहे हैं क्या है, बजाय के लिए उपलब्ध है की कोशिश कर रहा यह अपने आप को क्या करना है। सुरक्षा को लेकर आपकी जो भी धारणाएँ हैं, वे गलत हो सकती हैं। जैसा कि आपका अपना दृष्टिकोण सुरक्षित हो सकता है (और यह सबसे अच्छा लगता है), वहाँ एक जोखिम है जिसे आप कुछ देख रहे हैं और क्या आप वास्तव में उस मौके को लेना चाहते हैं जब यह सुरक्षा की बात आती है?

मापदंडों का उपयोग करें।


"जो भी विश्वसनीय, उद्योग मानक पुस्तकालय है उसका उपयोग करें" - क्या आप .NET के लिए एक की सिफारिश कर सकते हैं? शायद DB पर निर्भर करता है एक से अधिक: SQLServer, MySQL, PostgreSQL? मैंने एसक्यूएल-सैनिटाइज़र की तलाश की है, लेकिन बहुत अधिक भाग्य के बिना, इसलिए एचएसवीवी को अपने स्वयं के कार्यान्वयन के लिए मजबूर किया गया है, सबसे अच्छा मैं कर सकता हूं (जो कि मूर्खता से कोई संदेह नहीं है)।
पीएसयू

72

और फिर कोई व्यक्ति जाता है और "के बजाय" का उपयोग करता है। पैरामीटर हैं, आईएमओ, जाने का एकमात्र सुरक्षित तरीका।

यह तारीखों / संख्याओं के साथ बहुत सारे i18n मुद्दों से भी बचता है; दिनांक 01/02/03 क्या है? 123,456 कितनी है? क्या आपके सर्वर (ऐप-सर्वर और डीबी-सर्वर) एक-दूसरे से सहमत हैं?

यदि जोखिम कारक उनके लिए आश्वस्त नहीं है, तो प्रदर्शन के बारे में कैसे? RDBMS क्वेरी प्लान का उपयोग कर सकते हैं यदि आप मापदंडों का उपयोग करते हैं, तो प्रदर्शन में मदद करते हैं। यह सिर्फ स्ट्रिंग के साथ ऐसा नहीं कर सकता।


मैंने प्रारूपण और प्रदर्शन तर्क की कोशिश की है, लेकिन वे अभी भी आश्वस्त नहीं हैं।
रूण ग्रिमस्टैड

5
वास्तव में, sql सर्वर क्वेरी प्लान का पुन: उपयोग कर सकता है चाहे आप मापदंडों का उपयोग करें या नहीं। मैं अन्य तर्कों से सहमत हूं, लेकिन ज्यादातर मामलों के लिए पैरामीटराइज्ड एसक्यूएल के लिए प्रदर्शन तर्क अब नहीं उड़ता है।
tnyfst

1
@tnyfst: यह निष्पादन योजना का पुन: उपयोग कर सकता है जब क्वेरी स्ट्रिंग पैरामीटर मानों के हर संयोजन के लिए बदलता है? मैंने ऐसा संभव नहीं सोचा था।
जॉन सॉन्डर्स

4
यदि क्वेरी पाठ किसी पूर्ववर्ती क्वेरी पाठ के लिए IDENTICAL है, तो क्वेरी योजना पुन: उपयोग की जाएगी। इसलिए यदि आप EXACT SAME क्वेरी को दो बार भेजते हैं, तो इसका पुन: उपयोग किया जाएगा। हालाँकि, यदि आप केवल एक स्थान या अल्पविराम या कुछ और भी बदलते हैं, तो एक नई क्वेरी योजना निर्धारित करनी होगी।
marc_s

1
@ चेतावनी: मुझे यकीन नहीं है कि आप पूरी तरह से सही हैं। एसक्यूएल सर्वर कैशिंग hueristics एक छोटे से अजीब हैं। पार्सर पाठ में स्थिरांक की पहचान करने में सक्षम है और कृत्रिम रूप से उपयोग किए जाने वाले मापदंडों में से एक को SQL स्ट्रिंग में बदल सकता है। इसके बाद इस नई पैरामीटर वाली क्वेरी के टेक्स्ट को कैश में सम्मिलित कर सकते हैं। बाद में इसी तरह के एसक्यूएल को अपने पैरामीटर किए गए संस्करण को कैश में मिलान किया जा सकता है। हालाँकि, पैरामीटर किए गए संस्करणों का उपयोग हमेशा मूल SQL संस्करणों के बजाय कैश किए जाने के साथ नहीं किया जाता है, मुझे संदेह है कि SQL के पास दो दृष्टिकोणों के बीच चुनने के लिए एक zillion प्रदर्शन से संबंधित कारण हैं।
एंथनीवजोन

27

तर्क एक जीत नहीं है। यदि आप एक भेद्यता का पता लगाने का प्रबंधन करते हैं, तो आपके सहकर्मी इसके लिए खाता बनाने के लिए बस SafeDBString फ़ंक्शन को बदल देंगे और फिर आपको यह साबित करने के लिए कहेंगे कि यह फिर से असुरक्षित है।

यह देखते हुए कि पैराड्राइज्ड क्वेश्चन एक निर्विवाद प्रोग्रामिंग बेस्ट प्रैक्टिस है, सबूत का बोझ उन पर होना चाहिए कि वे ऐसा तरीका क्यों इस्तेमाल कर रहे हैं जो सुरक्षित और बेहतर प्रदर्शन करने वाला हो।

यदि समस्या सभी विरासत कोड को फिर से लिख रही है, तो आसान समझौता सभी नए कोड में पैराड्राइज्ड प्रश्नों का उपयोग करना होगा, और उस कोड पर काम करते समय उन्हें उपयोग करने के लिए पुराने कोड को रिफलेक्टर करना होगा।

मेरा अनुमान है कि वास्तविक मुद्दा गर्व और हठ है, और इसके बारे में आप बहुत कुछ नहीं कर सकते हैं।


19

सबसे पहले, "बदलें" संस्करण के लिए आपका नमूना गलत है। आपको पाठ के चारों ओर अपोस्ट्रोफ़्स डालने की आवश्यकता है:

string sql = "SELECT * FROM Users WHERE Name='" + SafeDBString(name) & "'";
SqlCommand getUser = new SqlCommand(sql, connection);

तो यह आपके लिए एक और बात है, पैरामीटर: आपको इस बारे में चिंता करने की ज़रूरत नहीं है कि क्या उद्धरण में एक मूल्य की आवश्यकता है या नहीं। बेशक, आप इसे फ़ंक्शन में बना सकते हैं, लेकिन फिर आपको फ़ंक्शन में बहुत अधिक जटिलता जोड़ने की आवश्यकता है: 'NULL' के रूप में null और 'NULL' के बीच के अंतर को केवल एक स्ट्रिंग के रूप में, या एक संख्या के बीच और कैसे पता करें एक स्ट्रिंग जिसमें बहुत सारे अंक होते हैं। यह कीड़े के लिए सिर्फ एक और स्रोत है।

एक और बात प्रदर्शन है: पैरामीटर किए गए क्वेरी प्लान अक्सर संक्षिप्त योजनाओं की तुलना में बेहतर तरीके से कैश किए जाते हैं, इस प्रकार क्वेरी को चलाते समय सर्वर को एक कदम बचा सकता है।

इसके अतिरिक्त, एकल उद्धरण से बचना काफी अच्छा नहीं है। कई DB उत्पाद उन पात्रों से बचने के लिए वैकल्पिक तरीकों की अनुमति देते हैं जो एक हमलावर लाभ उठा सकते थे। उदाहरण के लिए, MySQL में, आप बैकस्लैश के साथ एक भी उद्धरण से बच सकते हैं। और इसलिए निम्न "नाम" मान सिर्फ SafeDBString()फ़ंक्शन के साथ MySQL को उड़ा देगा , क्योंकि जब आप एकल उद्धरण को दोहराते हैं तो पहले वाला बैकस्लैश द्वारा बच जाता है, जिससे दूसरा "सक्रिय" हो जाता है:

x \ 'या 1 = 1 ;;


इसके अलावा, जूलियनआर नीचे एक अच्छा बिंदु लाता है: कभी भी सुरक्षा कार्य करने की कोशिश न करें। यह सूक्ष्म तरीके कि में सुरक्षा प्रोग्रामिंग गलत करना बहुत आसान है दिखाई देते हैं , काम करने के लिए भी पूरी तरह से परीक्षण के साथ। फिर समय बीत जाता है और एक साल बाद आपका पता चलता है कि आपका सिस्टम छह महीने पहले फटा था और आपको कभी यह पता भी नहीं चला।

अपने प्लेटफ़ॉर्म के लिए प्रदान किए गए सुरक्षा पुस्तकालयों पर हमेशा जितना संभव हो सके भरोसा करें। वे उन लोगों द्वारा लिखे जाएंगे जो एक जीवित के लिए सुरक्षा कोड करते हैं, जो आप प्रबंधित कर सकते हैं, और विक्रेता द्वारा सेवित होने की तुलना में बहुत बेहतर परीक्षण किया जाता है यदि एक भेद्यता पाई जाती है।


5
रिप्लेस फंक्शन एपोस्ट्रोफ्स जोड़ता है
रूण ग्रिमस्टैड

5
तब यह बग का सिर्फ एक और स्रोत है। यह कैसे पता चलता है कि NULL के बीच एक अशक्त मान और NULL के बीच एक पाठ स्ट्रिंग के रूप में अंतर है? या एक संख्या इनपुट और एक स्ट्रिंग के बीच जो सिर्फ अंकों को समाहित करने के लिए होता है?
जोएल कोएहॉर्न

अच्छी बात। आपको केवल स्ट्रिंग के लिए फ़ंक्शन का उपयोग करना चाहिए, और संभवतः तिथियां, इसलिए आपको सावधान रहना होगा। यह मापदंडों का उपयोग करने का एक और कारण है! वाह!
रूण ग्रिमस्टैड

10

तो मैं कहूंगा:

1) आप किसी ऐसी चीज को फिर से लागू करने की कोशिश क्यों कर रहे हैं जो अंदर बनी है? यह वहां उपलब्ध है, आसानी से उपलब्ध है, उपयोग करने में आसान है और पहले से ही वैश्विक स्तर पर डिबग किया गया है। यदि भविष्य में बग पाए जाते हैं, तो वे निश्चित हो जाएंगे और बिना कुछ किए ही बहुत जल्दी सभी के लिए उपलब्ध होंगे।

2) क्या प्रक्रियाओं की गारंटी है कि आप कभी भी SafeDBString को कॉल करने से नहीं चूकते हैं? केवल 1 स्थान पर गुम होने से मुद्दों की एक पूरी मेजबानी खुल सकती है। आप इन बातों पर कितना गौर करने जा रहे हैं, और विचार करें कि उस प्रयास को कितना बर्बाद किया है जब स्वीकार किए गए सही उत्तर तक पहुंचना इतना आसान है।

3) आप कितने निश्चित हैं कि आपने हर हमले के वेक्टर को कवर किया है जो Microsoft (DB और एक्सेस लाइब्रेरी के लेखक) को आपके SafeDBString कार्यान्वयन के बारे में पता है ...

4) एसक्यूएल की संरचना को पढ़ना कितना आसान है? उदाहरण + संघनन का उपयोग करता है, पैरामीटर स्ट्रिंग की तरह बहुत अधिक होते हैं। पोर्ट्रेट, जो अधिक पठनीय है।

इसके अलावा, काम करने के 2 तरीके हैं जो वास्तव में चलाए गए थे - अपना लॉगकोमैंड फ़ंक्शन, बिना सुरक्षा चिंताओं के एक साधारण फ़ंक्शन रोल करें , या यहां तक ​​कि डेटाबेस को लगता है कि वास्तव में क्या चल रहा है, यह काम करने के लिए एक एसक्यूएल ट्रेस को देखें।

हमारे LogCommand समारोह बस है:

    string LogCommand(SqlCommand cmd)
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine(cmd.CommandText);
        foreach (SqlParameter param in cmd.Parameters)
        {
            sb.Append(param.ToString());
            sb.Append(" = \"");
            sb.Append(param.Value.ToString());
            sb.AppendLine("\"");
        }
        return sb.ToString();
    }

सही या गलत, यह हमें वह जानकारी देता है जो हमें सुरक्षा मुद्दों के बिना चाहिए।


1
वह शायद पुराने VBSCRIPT प्रोग्रामर के एक झुंड से निपटने के लिए है, जो स्ट्रिंग कॉन्फैनेटेशन के माध्यम से XML और SQL सहित सब कुछ करने के लिए उपयोग किए जाते हैं। ये ऐसे लोग होंगे जो एक एपीआई के उपयोग से डरते हैं। वहाँ कुछ भी नहीं है कि उनके साथ किया जा सकता है, कम से कम कुछ भी नहीं मानवीय।
जॉन सॉन्डर्स

1
आइटम # 2 के लिए +1, इस अपवाद के साथ कि वास्तविक मापदंडों को लागू करने का कोई तरीका नहीं है।
जोएल कोएहॉर्न

7

पैरामीटर किए गए प्रश्नों के साथ आपको sql इंजेक्शन से सुरक्षा से अधिक मिलता है। आपको बेहतर निष्पादन योजना कैशिंग क्षमता भी मिलती है। यदि आप sql सर्वर क्वेरी प्रोफाइलर का उपयोग करते हैं, तब भी आप 'डेटाबेस पर चलाए जाने वाले सटीक sql' को देख सकते हैं, इसलिए आप अपने sql वक्तव्यों को डिबग करने के मामले में वास्तव में कुछ भी नहीं खो रहे हैं।


MySQL भी पैरामीटर मानों को उन में प्रक्षेपित परम मूल्यों के साथ लॉग करता है।
बिल कार्विन

5

मैंने एसक्यूएल इंजेक्शन हमलों से बचने के लिए दोनों तरीकों का इस्तेमाल किया है और निश्चित रूप से पैराट्राइज्ड प्रश्नों को प्राथमिकता दी है। जब मैंने संक्षिप्त प्रश्नों का उपयोग किया है तो मैंने चर (जैसे mysql_real_escape_string) से बचने के लिए एक लाइब्रेरी फ़ंक्शन का उपयोग किया है और मुझे विश्वास नहीं होगा कि मैंने सब कुछ एक मालिकाना कार्यान्वयन में कवर किया है (जैसा कि ऐसा लगता है कि आप भी हैं)।


2
+1 क्योंकि mysql_real_escape_string () \ x00, \ X1a, \ n \ r 'और "से बच जाता है। यह वर्ण सेट के मुद्दों को भी संभालता है। ओपी के सहकर्मी भोले समारोह में से कोई भी नहीं करते हैं!
बिल कार्विन

4

आप मापदंडों का उपयोग किए बिना उपयोगकर्ता इनपुट के किसी भी प्रकार की जांच आसानी से करने में सक्षम नहीं हैं।

यदि आप DBC कॉल करने के लिए SQLCommand और SQLParameter कक्षाओं का उपयोग करते हैं, तो आप अभी भी निष्पादित किए जा रहे SQL क्वेरी को देख सकते हैं। SQLCommand के CommandText गुण को देखें।

मैं हमेशा एसक्यूएल इंजेक्शन को रोकने के लिए रोल-योर-अप एप्रोच का संदेह करता हूं, जब पैरामीटर प्रश्नों का उपयोग करना आसान होता है। दूसरा, सिर्फ इसलिए कि "यह हमेशा इस तरह से किया गया है" इसका मतलब यह नहीं है कि यह इसे करने का सही तरीका है।


3

यह केवल तभी सुरक्षित है जब आपको गारंटी दी जाती है कि आप एक स्ट्रिंग में पास होने जा रहे हैं।

यदि आप किसी बिंदु पर एक तार में नहीं गुजर रहे हैं तो क्या होगा? क्या होगा अगर आप सिर्फ एक नंबर पास करें?

http://www.mywebsite.com/profile/?id=7;DROP DATABASE DB

अंत में बन जाएगा:

SELECT * FROM DB WHERE Id = 7;DROP DATABASE DB

यह एक स्ट्रिंग या एक संख्या है। SafeDbString के साथ एक स्ट्रिंग बच जाती है। एक नंबर एक Int32 है, और यह डेटाबेस को नहीं गिरा सकता है।
एंडोमर

नंबर को संभालना आसान है। आप क्वेरी में उपयोग करने से पहले पैरामीटर को एक इंट / फ्लोट / जो भी हो, में परिवर्तित कर सकते हैं। समस्या तब है जब आपको स्ट्रिंग डेटा को स्वीकार करना होगा।
रूण ग्रिमस्टैड

एंडोमर - यदि आप केवल हाथ से एक एसक्यूएल स्टेटमेंट का निर्माण कर रहे हैं, तो इसका इरादा "प्रकार" है कोई फर्क नहीं पड़ता, आप एसक्यूएल को एक नंबर के साथ बहुत आसानी से इंजेक्ट कर सकते हैं। रूण - मुझे लगता है कि यह मैन्युअल रूप से एसक्यूएल इंजेक्शन को हल करने की सभी बारीकियों को याद रखने के लिए व्यक्तिगत डेवलपर पर बहुत अधिक निर्भर है। यदि आप कहते हैं कि "मापदंडों का उपयोग करें" यह बहुत सरल है और वे गलत नहीं हो सकते।
joshcomley

@Andomar: NULL के बारे में क्या? या तार जो संख्या की तरह दिखते हैं?
जोएल कोएहॉर्न

2

मैं सब कुछ के लिए संग्रहीत कार्यविधियाँ या फ़ंक्शंस का उपयोग करूंगा, इसलिए सवाल नहीं उठेगा।

जहां मुझे एसक्यूएल को कोड में डालना है, मैं मापदंडों का उपयोग करता हूं, जो केवल एक चीज है जो समझ में आता है। असंतुष्टों को याद दिलाएं कि हैकर्स उससे कहीं ज्यादा होशियार हैं, और उस कोड को तोड़ने के लिए बेहतर प्रोत्साहन के साथ जो उन्हें आउटसोर्स करने की कोशिश कर रहा है। मापदंडों का उपयोग करना, यह बस संभव नहीं है, और ऐसा नहीं है कि यह मुश्किल है।


ठीक है, मापदंडों का उपयोग करके एसक्यूएल इंजेक्शन कैसे करें?
जॉन सॉन्डर्स

@ सैंडर्स: चरण 1 अपने DB के पैरामीटर-हैंडलिंग कार्यक्षमता में एक बफर अतिप्रवाह बग को खोजने के लिए है।
ब्रायन

2
अभी तक एक मिला? एक वाणिज्यिक DB में जो रोजाना हजारों-हजारों हैकरों द्वारा लोड किया जा रहा है? एक सॉफ्टवेयर कंपनी द्वारा बनाई गई जिसे बहुत गहरी जेब के लिए जाना जाता है? यदि संभव हो तो आप नाम से मुकदमे को उद्धृत कर सकेंगे ।
जॉन सॉन्डर्स

1
बेशक, sproc संयोजन और EXEC (बजाय sp_executesql का) आप मुसीबत में हों, तो वापस ... का उपयोग करता है (मैं इसे कई बार किया गलत छूट को देखा है यह ...)
मार्क Gravell

2

सुरक्षा के मुद्दों पर बेहद सहमत हैं।
मापदंडों का उपयोग करने का एक और कारण दक्षता के लिए है।

डेटाबेस हमेशा आपकी क्वेरी को संकलित करेगा और इसे कैश करेगा, फिर कैश्ड क्वेरी (जो बाद के अनुरोधों के लिए स्पष्ट रूप से तेज़ है) का उपयोग करें। यदि आप मापदंडों का उपयोग करते हैं, तो भले ही आप अलग-अलग मापदंडों का उपयोग करते हैं, डेटाबेस आपकी कैश की गई क्वेरी का उपयोग करेगा क्योंकि यह मापदंडों को बांधने से पहले SQL स्ट्रिंग के आधार पर मेल खाता है।

यदि आप मापदंडों को नहीं बांधते हैं, तो SQL स्ट्रिंग हर अनुरोध पर बदलता है (जिसमें अलग-अलग पैरामीटर हैं) और यह कभी भी मेल नहीं खाएगा कि आपके कैश में क्या है।


2

पहले से दिए गए कारणों के लिए, पैरामीटर एक बहुत अच्छा विचार है। लेकिन हम उनका उपयोग करने से नफरत करते हैं क्योंकि परम का निर्माण करते हैं और एक क्वेरी में बाद के उपयोग के लिए इसका नाम एक चर के लिए असाइन करते हैं एक ट्रिपल अप्रत्यक्ष सिर मलबे है।

निम्न वर्ग स्ट्रिंगर को लपेटता है जिसे आप आमतौर पर SQL अनुरोध बनाने के लिए उपयोग करेंगे। यह आपको पैरामीटर बनाने के बिना पैरामैटराइज़्ड क्वेरी लिखने देता है , जिससे आप SQL पर ध्यान केंद्रित कर सकते हैं। आपका कोड इस तरह दिखेगा ...

var bldr = new SqlBuilder( myCommand );
bldr.Append("SELECT * FROM CUSTOMERS WHERE ID = ").Value(myId, SqlDbType.Int);
//or
bldr.Append("SELECT * FROM CUSTOMERS WHERE NAME LIKE ").FuzzyValue(myName, SqlDbType.NVarChar);
myCommand.CommandText = bldr.ToString();

कोड पठनीयता, मुझे आशा है कि आप सहमत हैं, बहुत सुधार हुआ है, और आउटपुट एक उचित पैरामीटरयुक्त क्वेरी है।

वर्ग ऐसा दिखता है ...

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;

namespace myNamespace
{
    /// <summary>
    /// Pour le confort et le bonheur, cette classe remplace StringBuilder pour la construction
    /// des requêtes SQL, avec l'avantage qu'elle gère la création des paramètres via la méthode
    /// Value().
    /// </summary>
    public class SqlBuilder
    {
        private StringBuilder _rq;
        private SqlCommand _cmd;
        private int _seq;
        public SqlBuilder(SqlCommand cmd)
        {
            _rq = new StringBuilder();
            _cmd = cmd;
            _seq = 0;
        }
        //Les autres surcharges de StringBuilder peuvent être implémenté ici de la même façon, au besoin.
        public SqlBuilder Append(String str)
        {
            _rq.Append(str);
            return this;
        }
        /// <summary>
        /// Ajoute une valeur runtime à la requête, via un paramètre.
        /// </summary>
        /// <param name="value">La valeur à renseigner dans la requête</param>
        /// <param name="type">Le DBType à utiliser pour la création du paramètre. Se référer au type de la colonne cible.</param>
        public SqlBuilder Value(Object value, SqlDbType type)
        {
            //get param name
            string paramName = "@SqlBuilderParam" + _seq++;
            //append condition to query
            _rq.Append(paramName);
            _cmd.Parameters.Add(paramName, type).Value = value;
            return this;
        }
        public SqlBuilder FuzzyValue(Object value, SqlDbType type)
        {
            //get param name
            string paramName = "@SqlBuilderParam" + _seq++;
            //append condition to query
            _rq.Append("'%' + " + paramName + " + '%'");
            _cmd.Parameters.Add(paramName, type).Value = value;
            return this; 
        }

        public override string ToString()
        {
            return _rq.ToString();
        }
    }
}

1

बहुत कम समय से मुझे एसक्यूएल इंजेक्शन की समस्याओं की जांच करनी है, मैं देख सकता हूं कि मूल्य को 'सुरक्षित' बनाने का मतलब यह भी है कि आप उन स्थितियों के लिए दरवाजा बंद कर रहे हैं, जहां आप वास्तव में अपने डेटा में एपोस्ट्रोफिस चाहते हैं - किसी का नाम क्या है , ओ'रेली।

यह मापदंडों और संग्रहीत प्रक्रियाओं को छोड़ देता है।

और हां, आपको हमेशा सबसे अच्छे तरीके से कोड को लागू करने की कोशिश करनी चाहिए जो अब आप जानते हैं - न कि यह कि यह हमेशा कैसे किया जाता है।


डबल एपॉस्ट्रॉफ़्स को एसक्यूएल सर्वर द्वारा एक एकल एपोस्ट्रोफ में अनुवादित किया जाएगा, इसलिए ओ'रिली का नाम = 'ओ'रेली' में अनुवाद किया जाएगा
रूण ग्रिमस्टैड

जब उपयोगकर्ता अपने डेटा को देखना चाहता है तो क्या एपोस्ट्रोफ को निकालने के लिए एक समान कार्य है?
प्रातः

कोई जरुरत नहीं है। भागने का क्रम पार्सर को स्ट्रिंग के अंत के बजाय एक एकल उद्धरण देखने की अनुमति देता है। जैसा कि यह पार्सिंग है, यह ''एक शाब्दिक के रूप में देखता है ', इसलिए आपकी स्ट्रिंग को आंतरिक रूप से चरित्र अनुक्रम के रूप में देखा जाएगा O'Reilly। यही कारण है कि डीबी स्टोर करेगा, पुनर्प्राप्त करेगा, खिलाफ तुलना करेगा, आदि। यदि आप इसे बचने के बाद उपयोगकर्ता को अपना डेटा दिखाना चाहते हैं, तो बिना स्ट्रिंग स्ट्रिंग की एक प्रति रखें।
cHao

1

यहाँ कुछ लेख हैं जो आपको अपने सहकर्मियों को समझाने में सहायक हो सकते हैं।

http://www.sommarskog.se/dynamic_sql.html

http://unixwiz.net/techtips/sql-injection.html

व्यक्तिगत रूप से मैं अपने डेटाबेस को छूने के लिए किसी भी गतिशील कोड को कभी भी अनुमति देना पसंद नहीं करता, सभी संपर्कों को sps के माध्यम से होने की आवश्यकता होती है (और गतिशील एसक्यूएल का उपयोग नहीं करने वाला)। इसका मतलब यह नहीं है कि मैंने उपयोगकर्ताओं को क्या करने की अनुमति दी है और आंतरिक उपयोगकर्ता (व्यवस्थापक उद्देश्यों के लिए उत्पादन की पहुंच के साथ बहुत कम को छोड़कर) अपनी मेज तक सीधे नहीं पहुंच सकते हैं और डेटा चोरी या धोखाधड़ी कर सकते हैं। यदि आप एक वित्तीय अनुप्रयोग चलाते हैं, तो यह जाने का सबसे सुरक्षित तरीका है।


1

इसे तोड़ा जा सकता है, हालांकि साधन सटीक संस्करणों / पैच आदि पर निर्भर करता है।

जो पहले ही लाया जा चुका है वह अतिप्रवाह / छंटनी बग है जिसका दोहन किया जा सकता है।

एक अन्य भविष्य के साधन अन्य डेटाबेस के समान बग ढूंढ रहे होंगे - उदाहरण के लिए MySQL / PHP स्टैक एक भागने की समस्या का सामना करना पड़ा क्योंकि कुछ फ़ंक्शन को बदलने के लिए UTF8 अनुक्रम का उपयोग किया जा सकता है - इंजेक्शन फ़ंक्शन को शुरू करने में प्रतिस्थापित फ़ंक्शन को धोखा दिया जाएगा ।

दिन के अंत में, प्रतिस्थापन सुरक्षा तंत्र अपेक्षित पर निर्भर करता है, लेकिन इरादा नहीं कार्यक्षमता । चूंकि कार्यक्षमता कोड का इच्छित उद्देश्य नहीं था, इसलिए उच्च संभावना है कि कुछ खोजे गए क्वर्क आपकी अपेक्षित कार्यक्षमता को तोड़ देंगे।

यदि आपके पास बहुत अधिक विरासत कोड है, तो लंबी री राइटिंग और परीक्षण से बचने के लिए स्टॉपगैप के रूप में प्रतिस्थापित विधि का उपयोग किया जा सकता है। यदि आप नया कोड लिख रहे हैं, तो कोई बहाना नहीं है।


1

हमेशा जहाँ संभव हो, वहाँ पैरामीटर प्रश्नों का उपयोग करें। कभी-कभी किसी भी अजीब चरित्र के उपयोग के बिना एक सरल इनपुट पहले से ही एक SQL-इंजेक्शन बना सकता है अगर इसकी पहचान डेटाबेस में एक क्षेत्र के इनपुट के रूप में नहीं की जाती है।

तो बस डेटाबेस को इनपुट की पहचान करने का अपना काम करने दें, इसका उल्लेख नहीं करना भी मुसीबत का आवंटन बचाता है जब आपको वास्तव में अजीब पात्रों को सम्मिलित करने की आवश्यकता होती है जो अन्यथा बच जाएगी या बदल जाएगी। यह भी इनपुट की गणना नहीं करने के लिए अंत में कुछ मूल्यवान रनटाइम बचा सकता है।


1

मैंने किसी अन्य उत्तरदाता को 'क्यों अपने आप को बुरा कर रहा है' के इस पक्ष को संबोधित करते नहीं देखा, लेकिन SQL ट्रंकेशन हमले पर विचार करें ।

वहाँ भी है QUOTENAMET-SQL समारोह है कि यदि आप उन्हें पैरामीटर का उपयोग करने के लिए मनाने नहीं कर सकते सहायक हो सकता है। यह बची हुई qoute चिंताओं का एक बहुत (सभी?) पकड़ता है।


1

2 साल बाद , मैंने पुनर्विचार किया ... जो कोई भी पैरामीटर पाता है, वह मेरे वीएस एक्सटेंशन, क्वेरीफर्स्ट की । आप अपने अनुरोध को एक वास्तविक .sql फ़ाइल (मान्यता, Intellisense) में संपादित करते हैं। एक पैरामीटर जोड़ने के लिए, आप इसे सीधे अपने SQL में टाइप करते हैं, जो '@' से शुरू होता है। जब आप फ़ाइल को सहेजते हैं, तो क्वेरी चलाने और परिणामों को एक्सेस करने के लिए QueryFirst रैपर कक्षाएं उत्पन्न करेगा। यह आपके पैरामीटर के DB प्रकार को देखेगा और इसे एक .net प्रकार में मैप करेगा, जिसे आप जनरेट किए गए Execute () विधियों के इनपुट के रूप में पाएंगे। कोशिश करने के लिए स्वागत है सरल नहीं हो सका। इसे सही तरीके से करना किसी भी अन्य तरीके से करने की तुलना में मौलिक रूप से तेज और आसान है, और एक sql इंजेक्शन भेद्यता बनाना असंभव है, या कम से कम व्यापक रूप से कठिन है। ऐसे अन्य हत्यारे लाभ हैं, जैसे आपके DB में कॉलम को हटाने में सक्षम होना और तुरंत आपके एप्लिकेशन में संकलित त्रुटियां देखना।

कानूनी अस्वीकरण: मैंने QueryFirst लिखा


0

पैरामीटर किए गए प्रश्नों का उपयोग करने के कुछ कारण यहां दिए गए हैं:

  1. सुरक्षा - डेटाबेस एक्सेस लेयर यह जानती है कि डेटा में अनुमत वस्तुओं को कैसे निकालना या बचाना है।
  2. चिंताओं को अलग करना - डेटा को एक प्रारूप में बदलने के लिए मेरा कोड जिम्मेदार नहीं है जो डेटाबेस को पसंद है।
  3. कोई अतिरेक नहीं - मुझे हर प्रोजेक्ट में एक असेंबली या क्लास को शामिल करने की आवश्यकता नहीं है जो इस डेटाबेस को स्वरूपण / पलायन करता है; यह कक्षा पुस्तकालय में बनाया गया है।

0

कुछ भेद्यताएँ थीं (मुझे याद नहीं है कि यह कौन सा डेटाबेस था) जो SQL कथन के बफर अतिप्रवाह से संबंधित है।

मैं जो कहना चाहता हूं, SQL-Injection अधिक है तो बस "उद्धरण से बच", और आपको पता नहीं है कि आगे क्या आएगा।


0

एक अन्य महत्वपूर्ण विचार बच गए और गायब हुए डेटा पर नज़र रख रहा है। टन और टन के अनुप्रयोग हैं, वेब और अन्यथा, जब डेटा कच्चा-यूनिकोड, & -encoded, स्वरूपित HTML, et cetera, ठीक से नज़र रखने के लिए प्रतीत नहीं होता है। यह स्पष्ट है कि जो तार हैं उन पर नज़र रखना मुश्किल हो जाएगा'' और जो नहीं ।

जब आप कुछ चर के प्रकार को समाप्त करते हैं तो यह भी एक समस्या है - शायद यह एक पूर्णांक हुआ करता था, लेकिन अब यह एक स्ट्रिंग है। अब आपको एक समस्या है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.