2009-08-11 15 views
25

मुझे यह पूछने के लिए थोड़ा मूर्खतापूर्ण लगता है क्योंकि मैं दुनिया में एकमात्र व्यक्ति हूं जो इसे प्राप्त नहीं करता है, लेकिन यहां वैसे भी चला जाता है। मैं एक उदाहरण के रूप में पायथन का उपयोग करने जा रहा हूँ। जब मैं कच्चे एसक्यूएल प्रश्नों का उपयोग (मैं आमतौर पर ORMs का उपयोग करें) मैं का उपयोग कर parameterisation उपयोग करते हैं, इस उदाहरण की तरह SQLite:एसक्यूएल क्वेरी पैरामीटरेशन कैसे काम करता है?

विधि एक:

username = "wayne" 
query_params = (username) 
cursor.execute("SELECT * FROM mytable WHERE user=?", query_params) 

मैं इस काम करता है और मैं जानता हूँ कि यह आम तौर पर की सिफारिश की है ऐसा करने का तरीका

विधि बी::

username = "wayne" 
cursor.execute("SELECT * FROM mytable WHERE user='%s'" % username) 

जहाँ तक मुझे बता सकते हैं मैं एसक्यूएल इंजेक्शन को समझते हैं, के रूप में this Wikipedia article में विस्तार से बताया एक ही बात करने के लिए एक एसक्यूएल इंजेक्शन-कमजोर तरीका कुछ इस तरह होगा। मेरा सवाल बस है: तरीका ए विधि बी के लिए वास्तव में अलग कैसे है? विधि ए का अंतिम परिणाम विधि बी के समान क्यों नहीं है? मुझे लगता है कि cursor.execute() विधि (पायथन के डीबी-एपीआई विनिर्देश का हिस्सा) इनपुट से बचने और इनपुट की जांच करने का ख्याल रखता है, लेकिन यह कभी भी स्पष्ट रूप से कहीं भी नहीं कहा जाता है। क्या यह संदर्भ में सभी पैरामीटरकरण है? मेरे लिए, जब हम "पैरामीटरेशन" कहते हैं, तो इसका मतलब है "स्ट्रिंग प्रतिस्थापन", जैसे% -formatting। क्या यह गलत है?

+1

मैं संग्रहित प्रक्रियाओं के साथ यह प्रयोग करेंगे लेकिन अकेले यह एक अच्छा सवाल है। थोड़ा सा पढ़ने के बाद मुझे पता चला कि यह कैल्सबीक के नीचे है। पैरामीटरयुक्त क्वेरी पूरे उपयोगकर्ता नाम के रूप में 'वेने, ड्रॉप टेबल उपयोगकर्ता' को निर्देशों के एक और सेट के रूप में देखने के लिए नहीं देखेगी। इस पृष्ठ पर आखिरी टिप्पणी ने मुझे दिखाया कि: http://taylorza.blogspot.com/2009/04/sql-injection-are-parameterized-queries.html – johnny

उत्तर

34

एक पैरामीटरयुक्त क्वेरी वास्तव में स्ट्रिंग प्रतिस्थापन नहीं करती है। आप स्ट्रिंग प्रतिस्थापन का उपयोग करते हैं, तो एसक्यूएल इंजन वास्तव में एक प्रश्न ऐसा

SELECT * FROM mytable WHERE user='wayne' 

लगता है कि आप एक ? पैरामीटर का उपयोग करते देखता है, तो एसक्यूएल इंजन एक प्रश्न है कि लग रहा है

SELECT * FROM mytable WHERE user=<some value> 

की तरह देखता है जिसका मतलब है इससे पहले कि यह स्ट्रिंग "वेने" भी देखता है, यह क्वेरी को पूरी तरह से पार्स कर सकता है और समझ सकता है, आम तौर पर, क्वेरी क्या करती है। यह प्रश्न के अपने स्वयं के प्रतिनिधित्व में "वेने" चिपकता है, न कि SQL स्ट्रिंग जो क्वेरी का वर्णन करता है। इस प्रकार, एसक्यूएल इंजेक्शन असंभव है, क्योंकि हम पहले से ही प्रक्रिया के एसक्यूएल चरण पारित कर चुके हैं।

(ऊपर सामान्यीकृत है, लेकिन यह कम या ज्यादा विचार बता देते हैं।)

+2

तो अगर उसके पास रास्ता था; ड्रॉप टेबल खाते, किस प्रकार की त्रुटि क्या यह देगा? बस कोई परिणाम नहीं? – johnny

+5

@ जॉनी: इसे 'मायटेबल' से सबकुछ मिल जाएगा जहां 'उपयोगकर्ता'' रास्ता था, ड्रॉप टेबल खाते '। यह लिटिल बॉबी टेबल्स के वास्तविक रिकॉर्ड को वापस खींच देगा। – Eric

+0

@johny: ठीक है, कोई परिणाम नहीं। क्योंकि यह एक मान्य मूल्य है, भले ही यह बदसूरत हो। क्लाइंट और सर्वर के बीच बाइनरी-सुरक्षित प्रोटोकॉल उद्धरण, अर्धविराम या उसके जैसा कुछ भी नहीं करता है। – Javier

-1

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

सिस्टम तालिका master.dbo.syscacheobjects की जांच करें, और कुछ परीक्षण करें ताकि आप इस विषय पर कुछ और सीख सकें।

+0

जबकि यह SQL सर्वर विशिष्ट है, अधिकांश डेटाबेस इंजन इस तरह की चीजें करते हैं। निश्चित नहीं है कि SQLite (निर्दिष्ट इंजन) हालांकि करता है या नहीं। –

+0

यह समझने की अवधारणा से पूरी तरह से अलग है कि पैरामीटर किए गए प्रश्न क्या करते हैं और वे सुरक्षा लाभ क्यों प्रदान करते हैं। – Cheekysoft

+0

किसी भी गलतफहमी के लिए खेद है, इस तरह मैंने शुरुआत में यह समझना शुरू कर दिया कि मुझे अपनी स्ट्रिंग प्रतिस्थापन क्वेरी को प्रतिस्थापित क्यों करना है, इस सिस्टम तालिका में देख रहा हूं, और यह पता लगा रहा है कि मेरे प्रश्न सर्वर पर प्रक्रिया कैश को कठोर कर रहे हैं या नहीं। –

2

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

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

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

hum ... यह वास्तव में एक समानता नहीं था, यह वास्तव में हुड (लगभग) के तहत क्या हो रहा है।

+0

समानता ने मुझे तस्वीर पाने में मदद की, * मोटे तौर पर *। +1 –

2

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

यदि आपके पास MySQL चल रहा है, तो SQL लॉग चालू करें, और कुछ पैरामीटरयुक्त प्रश्नों को आज़माएं, और आप देखेंगे कि MySQL सर्वर को पूरी तरह से प्रतिस्थापित प्रश्न प्राप्त नहीं हो रहे हैं "?" इसमें, लेकिन MySQL क्लाइंट लाइब्रेरी आपके लिए आपके "पैरामीटर" में किसी भी उद्धरण से बच चुकी है।

तुम सिर्फ स्ट्रिंग प्रतिस्थापन के साथ विधि बी का उपयोग करते हैं, "s अपने आप बच गए नहीं हैं।

Synergetically, MySQL के साथ, आप एक पैरामिट्रीकृत क्वेरी समय से आगे तैयार कर सकते हैं, और फिर से तैयार बयान बार-बार बाद में उपयोग करें। जब आप एक प्रश्न तैयार करते हैं, MySQL इसे पार करता है और आपको एक तैयार कथन देता है - कुछ विश्लेषण किए गए प्रतिनिधित्व MySQL समझते हैं। प्रत्येक बार जब आप तैयार कथन का उपयोग करते हैं, न केवल आपको इंजेक्शन के खिलाफ संरक्षित किया जाता है, बल्कि आप फिर से क्वेरी को पार्स करने की लागत से बचते हैं

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

0

बस यहां एक चेतावनी। यह? सिंटैक्स ठीक काम करेगा और तारों में एम्बेडेड सिंगल या डबल कोट्स से बच निकलेगा।

हालांकि मुझे एक ऐसा मामला मिला जहां यह काम नहीं करता है। मेरे पास एक कॉलम है जो "n.n.n" फ़ॉर्म के संस्करण स्ट्रिंग को ट्रैक करता है उदा। "1.2.3" ऐसा लगता है कि प्रारूप एक त्रुटि का कारण बनता है क्योंकि यह दूसरे "।" तक वास्तविक संख्या की तरह दिखता है। उदाहरण के लिए:

rec = (some_value, '1.2.3') 
    sql = ''' UPDATE some_table 
       SET some_column=? 
       WHERE version=? ''' 
    cur = self.conn.cursor() 
    cur.execute(sql, rec) 

एक त्रुटि के साथ विफल "। आपूर्ति की बाइंडिंग की संख्या गलत है वर्तमान बयान 1 का उपयोग करता है, और 2 की आपूर्ति कर रहे हैं।"

यह ठीक काम करता है:

vers = '1.2.3' 
    rec = (some_value) 
    sql = ''' UPDATE some_table 
       SET some_column=? 
       WHERE version='%s' ''' % (vers) 
    cur = self.conn.cursor() 
    cur.execute(sql, rec) 
संबंधित मुद्दे