2013-12-09 14 views
9

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

तैयार क्वेरी और एक निर्मित क्वेरी का उपयोग करने के बीच व्यावहारिक अंतर क्या है जहां उपयोगकर्ता इनपुट हमेशा से sanitized है?

निर्माण

function quote($value) { 
    global $db; 
    return "'" . mysqli_real_escape_string($db, $value) . "'"; 
} 

$sql = "INSERT INTO foo (a, b) VALUES (" . quote($a) . "," . quote($b) . ")"; 

तैयार

$stmt = mysqli_prepare($db, "INSERT INTO foo (a, b) VALUES (?, ?)"); 
mysqli_stmt_bind_param($stmt, "ss", $a, $b); 
शब्दाडंबर और शैली से

के अलावा, क्या कारण मैं एक दूसरे के ऊपर का उपयोग करना चाहते हैं?

उत्तर

2

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

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

यह कहा गया है कि तैयार प्रश्न oversights के लिए बहुत कम प्रवण हैं, आमतौर पर बेहतर रखरखाव के परिणामस्वरूप।

संपादित करें: @ eggyal की टिप्पणी भी देखें कि क्यों तैयार बयानों हमेशा इंजेक्शन-सुरक्षित बच गए पैरामीटर के विपरीत सुरक्षित हैं।

+4

सहमत हैं, लेकिन ध्यान दें कि तैयार कथन के पैरामीटर सर्वर द्वारा SQL के लिए कभी भी पार्स नहीं किए जाते हैं, इसलिए एसक्यूएल के लिए इंजेक्शन के लिए यह असंभव * है; जबकि बचने के तरीके [हैं] [http://vigilance.fr/vulnerability/MySQL-SQL-injection-via-multi-byte-characters-5885) (और [इसके अधीन रहें] (http://stackoverflow.com/ ए/12118602)) शोषण योग्य भेद्यताएं, कुछ अस्पष्ट किनारे के मामलों में, सफल इंजेक्शन हमलों का कारण बन सकती हैं। – eggyal

+0

@eggyal: बिल्कुल। यही कारण है कि वे केवल कार्यात्मक रूप से समान हैं - वास्तव में - जैसा कि कहा गया है, ठीक से बच निकला। हालांकि, इसे ठीक से करना एक आसान काम नहीं है। – jwueller

+0

और यहां मैंने सोचा था कि पीडीओ हमें पढ़ने के लिए सभी @eggyal को बचाने जा रहा था http://stackoverflow.com/a/12118602 (नीचे ** खराब **) –

7

एक उत्कृष्ट सवाल।

पलायन

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

तैयार वक्तव्य

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

यदि आपको अलग-अलग मूल्यों के साथ एक ही क्वेरी को चलाने की आवश्यकता है, तो तैयार वक्तव्य आपको बहुत समय बचाते हैं। MySQL स्मृति में कथन को संग्रहीत करता है ताकि एकाधिक निष्पादन बहुत तेज़ हो।

आप अपनी क्वेरी के कुछ हिस्सों को पैरामीटर नहीं कर सकते हैं (यानी टेबल नाम)।

चेतावनी emptor

तो तैयार बयानों 100% सुरक्षित हैं, है ना? क्यों न सिर्फ सब कुछ के लिए तैयार बयान का उपयोग करें?हमने एसक्यूएल इंजेक्शन फॉरवर्ड हल कर लिया है! खैर, काफी नहीं। कुछ चेतावनी हैं जिन्हें आपको पहले के बारे में जानना है।

पहला mysqli पर विशिष्ट है। mysqli में परिणाम लौटने वाले तैयार बयान करने के लिए आप MySQL Native Driver (mysqlnd) स्थापित करना चाहते हैं। विशेष रूप से, mysqli_stmt_get_result, जो परिणाम सेट को mysqli_query जैसा देता है। कुछ साझा मेजबान और पुराने सर्वर अभी भी पुराने MySQL क्लाइंट लाइब्रेरी का उपयोग कर रहे हैं। यदि आप जानना चाहते हैं कि आप किसका उपयोग कर रहे हैं, तो phpinfo() चलाएं और mysqlnd ब्लॉक देखें। mysqlnd एक अच्छा विचार है भले ही आप तैयार कथन का उपयोग नहीं कर रहे हैं क्योंकि यह PHP टीम द्वारा विशेष रूप से MySQL से अधिक बनाने के लिए बनाया गया है। कुछ लोग ड्राइवर को नहीं बदल सकते हैं, हालांकि, यह एक सर्वर कॉन्फ़िगरेशन स्तर परिवर्तन है।

दूसरा उन लोगों के लिए है जो PDO (PHP में अपने डेटाबेस से कनेक्ट करने का एक और तरीका) का उपयोग करते हैं। अब, पीडीओ के पास तैयार बयानों को संभालने का एक बेहतर तरीका है (इसमें एक आसान एलियासिंग सिस्टम है) और तैयार बयान करने के लिए mysqlnd की आवश्यकता नहीं है। यहां चेतावनी यह है कि पीडीओ, डिफ़ॉल्ट रूप से, केवल तैयार बयानों को अनुकरण करता है, जिसका अर्थ है कि यदि आप इसे सही तरीके से कॉन्फ़िगर नहीं करते हैं, तो आप जो भी कर रहे हैं वह लाइब्रेरी का उपयोग कर रहा है जो आपके लिए बच निकलेगा। अधिक जानकारी के लिए PDO::ATTR_EMULATE_PREPARES के तहत this page देखें।

तीसरा सबसे दूर तक सबसे महत्वपूर्ण है और आपको यहां पर ध्यान देना होगा क्योंकि यदि आप सावधान नहीं हैं तो इससे आपके कार्यक्रम पर असर पड़ सकता है। अधिकतर लोग जो तैयार बयानों की वकालत करते हैं, वे यहां सबसे बड़ी गड़बड़ी को नजरअंदाज करते हैं, जो आप अपने डेटाबेस पर अधिक प्रश्न पूछ रहे हैं (यहां MySQL 5.5 manual सीएलआई के माध्यम से उन्हें कैसे करें)। अब, INSERT और UPDATE बयान के लिए जहां आप एक ही क्वेरी को चलाने के लिए जा रहे हैं और वहां कोई तुलना नहीं है। तैयार बयान आपको अपने समेकित समकक्षों पर बहुत समय बचाते हैं। लेकिन SELECT के लिए, यह बहुत कम स्पष्ट हो जाता है। ऊपर मेरा उदाहरण ले लो। यह autonumber क्षेत्र के माध्यम से एक रिकॉर्ड की एक साधारण खींच है। लेकिन एक के बजाय अब चलाने के लिए 2 प्रश्न लेते हैं। यदि यह कम यातायात वाला एक आंतरिक अनुप्रयोग है जो शायद एक बड़ा सौदा नहीं हो सकता है, लेकिन यदि उस पृष्ठ को दिन में 100,000 विचार मिलते हैं, तो हो सकता है कि आप उस पृष्ठ पर ओवरहेड को कम करना चाहें। यदि ऐसा है, तो सीधे सीधी क्वेरी बनाना आपके लिए एक समाधान हो सकता है।

तो, संक्षेप में

mysqli_real_escape_string कुछ नुकसान है, लेकिन जब तक आप उन कमियों को समझते हैं और आप और एसक्यूएल इंजेक्शन के बीच केवल सुरक्षा के रूप में यह इलाज नहीं है एक क्वेरी के लिए "पर्याप्त सुरक्षित" बनाया जा सकता है।

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

अन्य समाधान

  • Typecasting
  • श्वेत सूची (जहां आप यह सुनिश्चित पीएचपी के माध्यम से, (कुछ सीमाएं लेकिन वह असुरक्षित एसक्यूएल के लिए के साथ-साथ कुछ भी नहीं है), क्या मान होंगे भी या तो का उपयोग कर समाधान के बजाय उपयोगी कर सकते हैं स्वीकार्य और केवल उन मानों को अनुमति दें)

अंत में, यह पता लगाने के लिए आप कहां उपयुक्त हैं और दूसरे का उपयोग करने के लिए बेहतर हो सकता है।

+1

+1। गहराई से जवाब में बहुत अच्छा है। – jwueller

+0

दुर्भाग्यवश, भागने वाले भाग में यह विफल रहता है। स्पष्ट रूप से, यह इस हिस्से में बिल्कुल कोई समझ नहीं आता है। –

+0

और "बहुत समय" भाग में भी। –

-2

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

"निर्माण" के साथ दो गंभीर त्रुटियां हैं।

सबसे पहले, "निर्माण" आप मैनुअल के बारे में बात कर रहे हैं। इसका मतलब यह दो खतरों के लिए खुला है:

  • यह अलग स्वरूपण बनाता है। एक स्मार्ट प्रोग्रामर हमेशा कोड को "ऑप्टिमाइज़" करने का लुत्फ उठाएगा ... जिसके परिणामस्वरूप प्रक्रिया को स्वचालित करने के लिए पहले कोड में quote() कॉल किया गया था। जो सीधे आपदा का नेतृत्व करेगा, क्योंकि एक बड़ी परियोजना में एक चर या दो को अनदेखा करने का एक बहुत बड़ा मौका है, और उन्हें बिना स्वरूपित छोड़ दें।
  • मैन्युअल स्वरूपण हमेशा प्रोग्रामर के कौशल और मनोदशा पर निर्भर करता है। कुछ इसे ठीक करेंगे और कुछ असफल हो जाएंगे। यदि मैन्युअल है तो आप उचित स्वरूपण की गारंटी नहीं दे सकते।

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

दूसरा, एसक्यूएल सिंटैक्स केवल तारों तक ही सीमित नहीं है। कहें, आपका quote() फ़ंक्शन LIMIT क्लॉज पैरामीटर के साथ काम नहीं करेगा। तो आपको कुछ और बनाना होगा (या बस इंजेक्शन दें)।

मतलब आपको प्रत्येक प्रकार के एसक्यूएल शाब्दिक के लिए प्लेसहोल्डर होना है। Here is my attempt to accomplish the goal - एक लाइब्रेरी जो आपको सभी सामान्य डेटा प्रकारों के लिए प्लेसहोल्डर्स रखने देती है।

संबंधित मुद्दे