यदि हाँ, तो अभी भी इतने सफल SQL इंजेक्शन क्यों हैं? सिर्फ इसलिए कि कुछ डेवलपर्स पैरामीटराइज्ड स्टेटमेंट्स का उपयोग करने के लिए बहुत गूंगे हैं?
यदि हाँ, तो अभी भी इतने सफल SQL इंजेक्शन क्यों हैं? सिर्फ इसलिए कि कुछ डेवलपर्स पैरामीटराइज्ड स्टेटमेंट्स का उपयोग करने के लिए बहुत गूंगे हैं?
जवाबों:
मैंने अपनी टिप्पणियों में प्रश्न के लिए जो लिंक पोस्ट किए हैं वे समस्या को बहुत अच्छी तरह से समझाते हैं। मैंने अपनी भावनाओं को संक्षेप में बताया है कि समस्या क्यों बनी हुई है:
बस शुरू करने वालों को SQL इंजेक्शन के बारे में कोई जानकारी नहीं हो सकती है।
कुछ लोग SQL इंजेक्शन के बारे में जानते हैं, लेकिन सोचते हैं कि बचना ही (केवल?) समाधान है। यदि आप एक त्वरित Google खोज करते हैं php mysql query
, तो जो पहला पृष्ठ दिखाई देता है वह mysql_query
पृष्ठ है, जिस पर एक उदाहरण है जो एक इनपुट में भागे हुए उपयोगकर्ता इनपुट को इंटरपोलिंग दिखाता है। इसके बजाय तैयार बयानों का उपयोग करने का कोई उल्लेख नहीं है (कम से कम ऐसा नहीं है कि मैं देख सकता हूं)। जैसा कि दूसरों ने कहा है, वहाँ बहुत सारे ट्यूटोरियल हैं जो पैरामीटर प्रक्षेप का उपयोग करते हैं, कि यह वास्तव में आश्चर्यजनक नहीं है कि यह अभी भी कितनी बार उपयोग किया जाता है।
कैसे मानकीकृत बयान काम करते हैं, यह समझने की कमी है। कुछ लोग सोचते हैं कि यह मूल्यों से बचने का सिर्फ एक फैंसी साधन है।
अन्य लोग पैरामीटर किए गए कथनों से अवगत हैं, लेकिन उनका उपयोग न करें क्योंकि उन्होंने सुना है कि वे बहुत धीमे हैं। मुझे संदेह है कि कई लोगों ने सुना है कि कैसे अविश्वसनीय रूप से धीमी गति से paramterized बयान हैं, लेकिन वास्तव में स्वयं का कोई परीक्षण नहीं किया है। जैसा कि बिल कारविन ने अपनी बात में कहा, प्रदर्शन में अंतर को तैयार बयानों के उपयोग पर विचार करते समय शायद ही कभी एक कारक के रूप में इस्तेमाल किया जाना चाहिए। एक बार तैयार करने के लाभ , कई को निष्पादित करते हैं , अक्सर भूल जाते हैं, जैसा कि सुरक्षा और कोड रखरखाव में सुधार करते हैं।
कुछ हर जगह पैरामीटर स्टेटमेंट का उपयोग करते हैं, लेकिन टेबल और कॉलम के नाम, कीवर्ड और सशर्त ऑपरेटरों जैसे अनियंत्रित मूल्यों के प्रक्षेप के साथ। डायनामिक खोज, जैसे कि जो उपयोगकर्ताओं को कई अलग-अलग खोज फ़ील्ड निर्दिष्ट करने की अनुमति देती हैं, तुलना की स्थिति और क्रम क्रम, इसके प्रमुख उदाहरण हैं।
ORM का उपयोग करते समय सुरक्षा की गलत समझ। ORM अभी भी SQL कथन भागों के प्रक्षेप की अनुमति देते हैं - 5 देखें।
प्रोग्रामिंग एक बड़ा और जटिल विषय है, डेटाबेस प्रबंधन एक बड़ा और जटिल विषय है, सुरक्षा एक बड़ा और जटिल विषय है। एक सुरक्षित डेटाबेस एप्लिकेशन विकसित करना आसान नहीं है - यहां तक कि अनुभवी डेवलपर्स को भी पकड़ा जा सकता है।
Stackoverflow पर जवाब में से कई मदद नहीं करते हैं। जब लोग गतिशील एसक्यूएल और पैरामीटर प्रक्षेप का उपयोग करने वाले प्रश्न लिखते हैं, तो अक्सर उन प्रतिक्रियाओं की कमी होती है जो इसके बजाय मानकीकृत बयानों का उपयोग करने का सुझाव देते हैं। कुछ अवसरों पर, मैंने लोगों को तैयार किए गए बयानों का उपयोग करने के लिए अपने सुझाव को दोहराया है - आमतौर पर कथित अस्वीकार्य प्रदर्शन ओवरहेड के कारण। मुझे गंभीरता से संदेह है कि इनमें से अधिकांश प्रश्न पूछने वाले एक ऐसी स्थिति में हैं जहां एक पैरामीटरयुक्त विवरण तैयार करने के लिए लिए गए अतिरिक्त कुछ मिलीसेकंड उनके आवेदन पर एक भयावह प्रभाव डालेंगे।
जब लेख एसक्यूएल हमलों को रोकने के लिए पैरामीटरयुक्त प्रश्नों के बारे में बात करते हैं, तो वे वास्तव में यह नहीं समझाते हैं कि, यह अक्सर "ऐसा करता है, इसलिए यह मत पूछें" - संभवतः क्योंकि वे खुद को नहीं जानते हैं। एक बुरे शिक्षक का एक निश्चित संकेत यह है कि वे स्वीकार नहीं कर सकते कि वे कुछ नहीं जानते हैं। लेकिन मैं पीछे हटा। जब मैं कहता हूं कि मैंने पाया कि भ्रमित होना पूरी तरह से सरल है। एक गतिशील SQL क्वेरी की कल्पना करें
sqlQuery='SELECT * FROM custTable WHERE User=' + Username + ' AND Pass=' + password
इतना आसान sql इंजेक्शन सिर्फ 'या 1 = 1-- के रूप में यूजरनेम लगाने के लिए होगा। यह प्रभावी रूप से sql क्वेरी बना देगा:
sqlQuery='SELECT * FROM custTable WHERE User='' OR 1=1-- ' AND PASS=' + password
यह कहता है कि वे सभी ग्राहक चुनें जहां वे उपयोगकर्ता नाम रिक्त हैं ('') या 1 = 1, जो एक बूलियन है, जो सत्य के बराबर है। तब यह उपयोग करता है - बाकी क्वेरी से बाहर टिप्पणी करने के लिए। तो यह केवल सभी ग्राहक तालिका का प्रिंट आउट लेगा, या आप इसके साथ जो चाहें कर सकते हैं, यदि लॉग इन करते हैं, तो यह पहले उपयोगकर्ता के विशेषाधिकार के साथ लॉग इन करेगा, जो अक्सर व्यवस्थापक हो सकता है।
अब मानकीकृत प्रश्न इसे अलग तरह से करते हैं, जैसे कोड:
sqlQuery='SELECT * FROM custTable WHERE User=? AND Pass=?'
parameters.add("User", username)
parameters.add("Pass", password)
जहां उपयोगकर्ता नाम और पासवर्ड संबंधित इनपुट किए गए उपयोगकर्ता नाम और पासवर्ड की ओर इशारा करते हैं
अब इस बिंदु पर, आप सोच रहे होंगे, यह कुछ भी नहीं बदलता है। निश्चित रूप से आप अभी भी उपयोगकर्ता नाम फ़ील्ड में कुछ भी नहीं डाल सकते हैं जैसे कोई भी या 1 = 1 '-, प्रभावी रूप से क्वेरी बना रहा है:
sqlQuery='SELECT * FROM custTable WHERE User=Nobody OR 1=1'-- AND Pass=?'
और यह एक मान्य तर्क की तरह प्रतीत होगा। लेकिन तुम्हारी बात गलत सिद्ध होगी।
जिस तरह से क्वेरीज़ काम करती है, वह यह है कि sqlQuery को एक क्वेरी के रूप में भेजा जाता है, और डेटाबेस को ठीक से पता है कि यह क्वेरी क्या करेगी, और उसके बाद ही यह उपयोगकर्ता नाम और पासवर्ड को केवल मान के रूप में सम्मिलित करेगा। इसका मतलब है कि वे क्वेरी को प्रभावित नहीं कर सकते, क्योंकि डेटाबेस पहले से ही जानता है कि क्वेरी क्या करेगी। तो इस मामले में यह "कोई नहीं 1 = 1 '-" का उपयोगकर्ता नाम और एक रिक्त पासवर्ड होगा, जो कि गलत होना चाहिए।
हालांकि यह पूर्ण समाधान नहीं है, और इनपुट सत्यापन को अभी भी करने की आवश्यकता होगी, क्योंकि यह अन्य समस्याओं को प्रभावित नहीं करेगा, जैसे कि XSS हमले, जैसा कि आप अभी भी डेटाबेस में जावास्क्रिप्ट डाल सकते हैं। फिर यदि इसे किसी पृष्ठ पर पढ़ा जाता है, तो यह किसी भी आउटपुट सत्यापन के आधार पर, इसे सामान्य जावास्क्रिप्ट के रूप में प्रदर्शित करेगा। तो वास्तव में सबसे अच्छी बात यह है कि अभी भी इनपुट सत्यापन का उपयोग किया जाता है, लेकिन किसी भी एसक्यूएल हमलों को रोकने के लिए मानकीकृत प्रश्नों या संग्रहीत प्रक्रियाओं का उपयोग करना।
अच्छा सवाल है। उत्तर निर्धारक की तुलना में अधिक स्टोचस्टिक है और मैं एक छोटे से उदाहरण का उपयोग करते हुए अपने दृष्टिकोण को समझाने की कोशिश करूंगा।
नेट पर ऐसे कई संदर्भ हैं जो हमें एसक्यूएल इंजेक्शन (एसक्यूआई) से बचने के लिए हमारे प्रश्नों में मापदंडों का उपयोग करने या मापदंडों के साथ संग्रहीत प्रक्रिया का उपयोग करने का सुझाव देते हैं। मैं आपको दिखाऊंगा कि संग्रहीत प्रक्रियाएँ (उदाहरण के लिए) SQLi के विरुद्ध कोई जादुई छड़ी नहीं है। जिम्मेदारी अभी भी प्रोग्रामर पर बनी हुई है।
निम्न SQL सर्वर संग्रहित प्रक्रिया पर विचार करें जो तालिका 'उपयोगकर्ता' से उपयोगकर्ता पंक्ति प्राप्त करेगी:
create procedure getUser
@name varchar(20)
,@pass varchar(20)
as
declare @sql as nvarchar(512)
set @sql = 'select usrID, usrUName, usrFullName, usrRoleID '+
'from Users '+
'where usrUName = '''+@name+''' and usrPass = '''+@pass+''''
execute(@sql)
आप उपयोगकर्ता नाम और पासवर्ड पैरामीटर के रूप में पास करके परिणाम प्राप्त कर सकते हैं। पासवर्ड को मुफ़्त पाठ में मान लेना (केवल इस उदाहरण की सादगी के लिए) एक सामान्य कॉल होगी:
DECLARE @RC int
DECLARE @name varchar(20)
DECLARE @pass varchar(20)
EXECUTE @RC = [dbo].[getUser]
@name = 'admin'
,@pass = '!@Th1siSTheP@ssw0rd!!'
GO
लेकिन यहां हमारे पास प्रोग्रामर द्वारा संग्रहीत प्रक्रिया के अंदर उपयोग की जाने वाली एक खराब प्रोग्रामिंग तकनीक है, इसलिए एक हमलावर निम्नलिखित को निष्पादित कर सकता है:
DECLARE @RC int
DECLARE @name varchar(20)
DECLARE @pass varchar(20)
EXECUTE @RC = [TestDB].[dbo].[getUser]
@name = 'admin'
,@pass = 'any'' OR 1=1 --'
GO
उपरोक्त मापदंडों को संग्रहीत प्रक्रिया के तर्क के रूप में पारित किया जाएगा और SQL कमांड जिसे अंततः निष्पादित किया जाएगा:
select usrID, usrUName, usrFullName, usrRoleID
from Users
where usrUName = 'admin' and usrPass = 'any' OR 1=1 --'
.. जो उपयोगकर्ताओं से सभी पंक्तियों को वापस मिलेगा
यहां समस्या यह है कि यहां तक कि हम उस सिद्धांत का पालन करते हैं "एक संग्रहीत प्रक्रिया बनाएं और मापदंडों के रूप में खोज करने के लिए फ़ील्ड पास करें" एसक्यूआई अभी भी किया जाता है। ऐसा इसलिए है क्योंकि हम अपनी खराब प्रोग्रामिंग प्रैक्टिस को सिर्फ स्टोर की गई प्रक्रिया के अंदर कॉपी करते हैं। समस्या का समाधान हमारी संग्रहित प्रक्रिया को फिर से लिखना है:
alter procedure getUser
@name varchar(20)
,@pass varchar(20)
as
select usrID, usrUName, usrFullName, usrRoleID
from Users
where usrUName = @name and usrPass = @pass
मैं जो कहना चाह रहा हूं, वह यह है कि डेवलपर्स को पहले यह सीखना चाहिए कि SQLi अटैक क्या है और कैसे किया जा सकता है और फिर उसी के अनुसार अपने कोड को सुरक्षित रखना है। नेत्रहीन रूप से 'सर्वोत्तम प्रथाओं' का पालन करना हमेशा सुरक्षित तरीका नहीं होता है ... और शायद इसीलिए हमारे पास बहुत सारी 'सर्वोत्तम प्रथाएँ' हैं- असफलताएँ!
हां, तैयार किए गए बयानों का उपयोग सभी एसक्यूएल इंजेक्शन को रोकता है, कम से कम सिद्धांत में। व्यवहार में, पैरामीटर किए गए कथन वास्तविक रूप से तैयार किए गए कथन नहीं हो सकते हैं, उदाहरण PDO
के लिए PHP में डिफ़ॉल्ट रूप से उनका अनुकरण करता है इसलिए यह एक किनारे के मामले के हमले के लिए खुला है ।
यदि आप वास्तविक तैयार बयानों का उपयोग कर रहे हैं, तो सब कुछ सुरक्षित है। ठीक है, कम से कम जब तक आप अपनी क्वेरी में असुरक्षित एसक्यूएल को प्रतिक्रिया में नहीं लेते हैं, उदाहरण के लिए तालिका के नाम तैयार करने में सक्षम नहीं हैं।
यदि हाँ, तो अभी भी इतने सफल SQL इंजेक्शन क्यों हैं? सिर्फ इसलिए कि कुछ डेवलपर्स पैरामीटराइज्ड स्टेटमेंट्स का उपयोग करने के लिए बहुत गूंगे हैं?
हां, शिक्षा यहां मुख्य बिंदु है, और विरासत कोड आधार है। कई ट्यूटोरियल बचने का उपयोग करते हैं और जिन्हें आसानी से वेब से हटाया नहीं जा सकता है, दुर्भाग्य से।
मैं प्रोग्रामिंग में निरपेक्षता से बचता हूं; हमेशा एक अपवाद होता है। मैं संग्रहीत प्रक्रियाओं और कमांड ऑब्जेक्ट्स की अत्यधिक अनुशंसा करता हूं। मेरे बैक ग्राउंड का अधिकांश हिस्सा SQL सर्वर के साथ है, लेकिन मैं समय-समय पर MySql के साथ खेलता हूं। कैश्ड क्वेरी योजनाओं सहित संग्रहीत कार्यविधियों के कई फायदे हैं; हां, यह मापदंडों और इनलाइन SQL के साथ पूरा किया जा सकता है, लेकिन यह इंजेक्शन हमलों के लिए अधिक संभावनाएं खोलता है और चिंताओं को अलग करने में मदद नहीं करता है। मेरे लिए डेटाबेस को सुरक्षित करना भी बहुत आसान है क्योंकि मेरे आवेदन में आमतौर पर केवल उक्त संग्रहीत प्रक्रियाओं के लिए अनुमति होती है। प्रत्यक्ष तालिका / दृश्य पहुंच के बिना कुछ भी इंजेक्षन करना अधिक कठिन है। यदि उपयोगकर्ता से छेड़छाड़ की जाती है, तो केवल उसी को निष्पादित करने की अनुमति होती है, जो पहले से परिभाषित था।
मेरे दो सेंट।
मैं "गूंगा" नहीं कहूंगा।
मुझे लगता है कि ट्यूटोरियल समस्या है। अधिकांश SQL ट्यूटोरियल, किताबें, जो भी SQL को इनलाइन मानों के साथ समझाते हैं, बाइंड मापदंडों का उल्लेख नहीं करते हैं। इन ट्यूटोरियल से सीखने वाले लोगों के पास इसे सीखने का मौका नहीं है।
क्योंकि अधिकांश कोड सुरक्षा को ध्यान में रखते हुए नहीं लिखे गए हैं, और प्रबंधन, सुविधाओं को जोड़ने के बीच एक विकल्प दिया गया है (विशेष रूप से दिखाई जाने वाली कुछ चीज़ों को बेचा जा सकता है) और सुरक्षा / स्थिरता / विश्वसनीयता (जो कि अधिक कठिन बिकती है) वे लगभग हमेशा चुन लेंगे पूर्व। सुरक्षा केवल एक चिंता का विषय है जब यह एक समस्या बन जाती है।
क्या पैरामीटर स्टेटमेंट सभी एसक्यूएल इंजेक्शन को रोक सकता है?
हां, जब तक कि आपका डेटाबेस ड्राइवर हर संभव एसक्यूएल शाब्दिक के लिए एक प्लेसहोल्डर प्रदान करता है । अधिकांश तैयार स्टेटमेंट ड्राइवर नहीं करते हैं। कहते हैं, आपको कभी भी फ़ील्ड नाम या मानों के लिए प्लेसहोल्डर नहीं मिलेगा। जो एक डेवलपर को कंसीलरेशन और मैनुअल फॉर्मेटिंग का उपयोग करते हुए एक क्वेरी को हाथ से वापस गिराने के लिए बना देगा। अनुमानित परिणाम के साथ।
यही कारण है कि मैंने PHP के लिए अपना मैसूरल रैपर बनाया है जो क्वेरी और डायनॉजिस्ट सहित गतिशील रूप से क्वेरी में जोड़े जा सकने वाले अधिकांश शाब्दिक समर्थन करता है।
यदि हाँ, तो अभी भी इतने सफल SQL इंजेक्शन क्यों हैं? सिर्फ इसलिए कि कुछ डेवलपर्स पैरामीटराइज्ड स्टेटमेंट्स का उपयोग करने के लिए बहुत गूंगे हैं?
जैसा कि आप देख सकते हैं, वास्तव में आपके सभी प्रश्नों को मानकीकृत करना असंभव है , भले ही आप गूंगे न हों।
आपके पहले सवाल का पहला जवाब: हां, जहां तक मुझे पता है, पैरामीटर किए गए प्रश्नों का उपयोग करके, SQL इंजेक्शन अब संभव नहीं होगा। आपके निम्नलिखित प्रश्नों के अनुसार, मुझे यकीन नहीं है और मैं आपको केवल कारणों पर अपनी राय दे सकता हूं:
मुझे लगता है कि "बस" कुछ अलग-अलग हिस्सों (शायद कुछ तार्किक जांचों पर भी निर्भर) को सम्मिलित करने के लिए एक साथ एसक्यूएल क्वेरी स्ट्रिंग को लिखना आसान है। यह केवल क्वेरी बना रहा है और इसे निष्पादित कर रहा है। एक और लाभ यह है कि आप sql क्वेरी स्ट्रिंग को प्रिंट (इको, आउटपुट या जो भी) कर सकते हैं और फिर डेटाबेस इंजन के लिए एक मैनुअल क्वेरी के लिए इस स्ट्रिंग का उपयोग कर सकते हैं।
तैयार किए गए कथनों के साथ काम करते समय, आपके पास हमेशा कम से कम एक कदम अधिक होता है: आपको अपनी क्वेरी बनानी होगी (मापदंडों सहित, निश्चित रूप से) आपको सर्वर पर क्वेरी तैयार करनी होगी आपको अपने इच्छित मानों के लिए मापदंडों को बांधना होगा। अपनी क्वेरी के लिए उपयोग करने के लिए आपको क्वेरी को निष्पादित करना होगा।
यह कुछ अधिक काम है (और कार्यक्रम के लिए इतना सीधा नहीं) विशेष रूप से कुछ "त्वरित और गंदे" नौकरियों के लिए जो अक्सर बहुत बड़े-बड़े साबित होते हैं ...
सादर,
डिब्बा
SQL इंजेक्शन कोड इंजेक्शन की बड़ी समस्या का एक सबसेट है, जहां डेटा और कोड एक ही चैनल पर प्रदान किए जाते हैं और डेटा को कोड के लिए गलत किया जाता है। डेटा और क्या कोड है के बारे में संदर्भ का उपयोग करके क्वेरी के गठन से पैरामीटर को रोकें।
कुछ विशिष्ट मामलों में, यह पर्याप्त नहीं है। कई DBMSes में, DBMS स्तर पर SQL इंजेक्शन दोष का परिचय देते हुए, SQL को संग्रहीत प्रक्रियाओं के साथ गतिशील रूप से निष्पादित करना संभव है। पैरामीटर किए गए प्रश्नों का उपयोग करके ऐसी संग्रहीत प्रक्रिया को कॉल करने से प्रक्रिया में SQL इंजेक्शन को शोषण होने से नहीं रोका जा सकेगा। एक और उदाहरण इस ब्लॉग पोस्ट में देखा जा सकता है ।
अधिक सामान्यतः, डेवलपर्स गलत तरीके से कार्यक्षमता का उपयोग करते हैं। आमतौर पर कोड कुछ ऐसा दिखता है जब सही तरीके से किया जाता है:
db.parameterize_query("select foo from bar where baz = '?'", user_input)
कुछ डेवलपर्स एक साथ तारों को समतल करेंगे और फिर एक पैरामीटर क्वेरी का उपयोग करेंगे, जो वास्तव में उपरोक्त डेटा / कोड भेद नहीं करता है जो हमें सुरक्षा गारंटी प्रदान करता है:
db.parameterize_query("select foo from bar where baz = '" + user_input + "'")
पैरामीटर किए गए प्रश्नों का सही उपयोग बहुत मजबूत प्रदान करता है, लेकिन अभेद्य नहीं है, SQL इंजेक्शन हमलों के खिलाफ सुरक्षा।
अपने एप्लिकेशन को SQL इंजेक्शन से बचाने के लिए, निम्न चरणों का पालन करें:
चरण 1. बाधा इनपुट। चरण 2. संग्रहीत प्रक्रियाओं के साथ मापदंडों का उपयोग करें। चरण 3. गतिशील एसक्यूएल के साथ मापदंडों का उपयोग करें।
Http://msdn.microsoft.com/en-us/library/ff648339.aspx का संदर्भ लें
भले ही तैयार किए गए बयानों का उपयोग वेब एप्लिकेशन के अपने कोड में ठीक से किया गया हो, यदि SQL कोड घटक असुरक्षित तरीके से उपयोगकर्ता इनपुट से क्वेरी का निर्माण करते हैं, तो SQL इंजेक्शन की खामियां अभी भी मौजूद हो सकती हैं। निम्न संग्रहीत कार्यविधि का एक उदाहरण है जो @name पैरामीटर में SQL इंजेक्शन के लिए असुरक्षित है:
CREATE PROCEDURE show_current_orders
(@name varchar(400) = NULL)
AS
DECLARE @sql nvarchar(4000)
SELECT @sql = ‘SELECT id_num, searchstring FROM searchorders WHERE ‘ +
‘searchstring = ‘’’ + @name + ‘’’’;
EXEC (@sql)
GO
भले ही अनुप्रयोग सुरक्षित तरीके से संग्रहीत प्रक्रिया के लिए उपयोगकर्ता द्वारा आपूर्ति किए गए नाम मान को पास करता है, प्रक्रिया खुद को एक गतिशील क्वेरी में सीधे समेटती है और इसलिए कमजोर होती है।