php पीडीओ एसक्यूएल इंजेक्शन को रोकने के लिए पर्याप्त बयान तैयार हैं?




security pdo (6)

मान लें कि मेरे पास कोड है:

$dbh = new PDO("blahblah");

$stmt = $dbh->prepare('SELECT * FROM users where username = :username');
$stmt->execute( array(':username' => $_REQUEST['username']) );

पीडीओ दस्तावेज कहता है:

तैयार बयानों के मानकों को उद्धृत करने की आवश्यकता नहीं है; चालक इसे आपके लिए संभालता है।

एसक्यूएल इंजेक्शन से बचने के लिए मुझे वास्तव में क्या करना है? क्या वाकई वह इतना आसान है?

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


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

आप जेएस को अक्षम कर सकते हैं या एक फ्रंट एंड डेवलपमेंट टूल के साथ एक पैटर्न संपादित कर सकते हैं (आजकल फ़ायरफ़ॉक्स या क्रोम के साथ निर्मित)।

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

मैं आपको GET और INPUT मानों को स्वच्छ करने के लिए फ़िल्टर_इनपुट () मूल PHP फ़ंक्शन का उपयोग करने के लिए सुझाव देना चाहता हूं।

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

सुरक्षा की लागत है, लेकिन अपना प्रदर्शन बर्बाद मत करो!

आसान उदाहरण:

यदि आप दोबारा जांचना चाहते हैं कि जीईटी से प्राप्त मूल्य एक नंबर है, तो 99 से कम (अगर preg_match ('/ [0-9] {1,2} /')) {...} भारी है

if (isset($value) && intval($value)) <99) {...}

तो, अंतिम जवाब यह है: "नहीं! पीडीओ तैयार वक्तव्य सभी प्रकार के एसक्यूएल इंजेक्शन को रोकता नहीं है"; यह अप्रत्याशित मूल्यों को नहीं रोकता है, केवल अप्रत्याशित concatenation


नहीं यह पर्याप्त नहीं है (कुछ विशिष्ट मामलों में)! डिफ़ॉल्ट रूप से पीडीओ डेटाबेस ड्राइवर के रूप में MySQL का उपयोग करते समय नकली तैयार बयान का उपयोग करता है। MySQL और PDO का उपयोग करते समय आपको हमेशा नकली तैयार कथन अक्षम करना चाहिए:

$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

एक और चीज जो हमेशा किया जाना चाहिए, यह डेटाबेस के सही एन्कोडिंग को सेट करता है:

$dbh = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');

यह संबंधित प्रश्न भी देखें: मैं PHP में एसक्यूएल इंजेक्शन को कैसे रोक सकता हूं?

यह भी ध्यान रखें कि केवल उन चीजों के डेटाबेस पक्ष के बारे में है जिन्हें डेटा प्रदर्शित करते समय आपको स्वयं को देखना होगा। जैसे कि सही एन्कोडिंग और उद्धरण शैली के साथ htmlspecialchars() का उपयोग करके।


तैयार कथन / पैरामीटरयुक्त प्रश्न आमतौर पर उस कथन * पर 1 ऑर्डर इंजेक्शन को रोकने के लिए पर्याप्त होते हैं। यदि आप अपने आवेदन में कहीं भी अन-चेक किए गए गतिशील एसक्यूएल का उपयोग करते हैं तो आप अभी भी दूसरे ऑर्डर इंजेक्शन के लिए कमजोर हैं।

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

आप दूसरे ऑर्डर इंजेक्शन अटैक को पूरा कर सकते हैं जब आप किसी डेटाबेस में एक मान को संग्रहीत करने का कारण बन सकते हैं जिसे बाद में क्वेरी में शाब्दिक के रूप में उपयोग किया जाता है। उदाहरण के तौर पर, मान लीजिए कि आप किसी वेबसाइट पर खाता बनाते समय अपना नया उपयोगकर्ता नाम के रूप में निम्न जानकारी दर्ज करते हैं (इस प्रश्न के लिए MySQL डीबी मानते हैं):

' + (SELECT UserName + '_' + Password FROM Users LIMIT 1) + '

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

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

* यह पता चला है कि MySQL / PHP हैं (ठीक है, थे) विस्तृत अक्षर शामिल होने पर पैरामीटर को संभालने के बारे में सिर्फ गूंगा है, और यहां पर एक अत्यधिक दुर्लभ मामला है जो यहां अत्यधिक उच्च वोट वाले उत्तर में उल्लिखित है जो इंजेक्शन को पैरामीटरकृत के माध्यम से पर्ची करने की अनुमति दे सकता है क्वेरी।


नहीं, वे हमेशा नहीं होते हैं।

यह इस बात पर निर्भर करता है कि क्या आप उपयोगकर्ता इनपुट को क्वेरी के भीतर ही रखने की अनुमति देते हैं। उदाहरण के लिए:

$dbh = new PDO("blahblah");

$tableToUse = $_GET['userTable'];

$stmt = $dbh->prepare('SELECT * FROM ' . $tableToUse . ' where username = :username');
$stmt->execute( array(':username' => $_REQUEST['username']) );

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

$dbh = new PDO("blahblah");

$tableToUse = $_GET['userTable'];
$allowedTables = array('users','admins','moderators');
if (!in_array($tableToUse,$allowedTables))    
 $tableToUse = 'users';

$stmt = $dbh->prepare('SELECT * FROM ' . $tableToUse . ' where username = :username');
$stmt->execute( array(':username' => $_REQUEST['username']) );

नोट: आप डीडीएल (डेटा परिभाषा भाषा) के बाहर जाने वाले डेटा को बाध्य करने के लिए पीडीओ का उपयोग नहीं कर सकते हैं, यानी यह काम नहीं करता है:

$stmt = $dbh->prepare('SELECT * FROM foo ORDER BY :userSuppliedData');

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


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


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

पैरामीटर प्रश्न कोड और डेटा को अलग से भेजकर काम करते हैं, इसलिए इसमें कोई छेद नहीं खोजना संभव नहीं होगा।

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





sql-injection