क्या SQL इंजेक्शन को रोकने के लिए PDO तैयार स्टेटमेंट पर्याप्त हैं?


661

मान लीजिए कि मेरे पास इस तरह का कोड है:

$dbh = new PDO("blahblah");

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

पीडीओ प्रलेखन कहता है:

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

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

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


5
बेहतर दृष्टिकोण 7 वें नंबर का जवाब stackoverflow.com/questions/134099/…
NullPoiиteя

जवाबों:


807

संक्षिप्त उत्तर नहीं है , पीडीओ की तैयारी आपको हर संभव SQL-Injection हमलों से बचाव नहीं करेगी। कुछ अस्पष्ट किनारे के मामलों के लिए।

मैं पीडीओ के बारे में बात करने के लिए इस उत्तर को स्वीकार कर रहा हूं ...

लंबा जवाब इतना आसान नहीं है। यह यहां प्रदर्शित एक हमले पर आधारित है ।

हमला

तो, आइए हम हमले को दिखाते हुए शुरू करें ...

$pdo->query('SET NAMES gbk');
$var = "\xbf\x27 OR 1=1 /*";
$query = 'SELECT * FROM test WHERE name = ? LIMIT 1';
$stmt = $pdo->prepare($query);
$stmt->execute(array($var));

कुछ परिस्थितियों में, यह 1 से अधिक पंक्ति में लौटेगा। चलो यहाँ क्या चल रहा है:

  1. कैरेक्टर सेट का चयन करना

    $pdo->query('SET NAMES gbk');

    काम करने के लिए इस हमले के लिए, हम एन्कोडिंग की जरूरत है कि सर्वर के दोनों एनकोड करने के लिए कनेक्शन पर उम्मीद 'ASCII यानी के रूप में 0x27 और कुछ चरित्र जिसका अंतिम बाइट एक ASCII है के लिए \यानी 0x5c। यह पता चला है के रूप में, 5 ऐसे डिफ़ॉल्ट रूप से MySQL 5.6 में समर्थित एनकोडिंग हैं: big5, cp932, gb2312, gbkऔर sjis। हम gbkयहाँ का चयन करेंगे ।

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

  2. पेलोड

    इस इंजेक्शन के लिए हम जिस पेलोड का उपयोग करने जा रहे हैं, वह बाइट अनुक्रम से शुरू होता है 0xbf27। में gbk, यह एक अमान्य मल्टीबाइट चरित्र है; में latin1, यह स्ट्रिंग है ¿'। ध्यान दें कि में latin1 और gbk , 0x27पर अपने आप ही एक शाब्दिक है 'चरित्र।

    हमने इस पेलोड को चुना है, क्योंकि अगर हमने इस addslashes()पर कॉल किया , तो हम चरित्र से पहले एक ASCII \यानी सम्मिलित करेंगे । तो हम एक साथ एक दो चरित्र अनुक्रम है , जिसके साथ हवा होगी : द्वारा पीछा किया । या दूसरे शब्दों में, एक वैध चरित्र जिसके बाद एक गैर-पंजीकृत व्यक्ति आता है । लेकिन हम उपयोग नहीं कर रहे हैं । तो अगले कदम पर ...0x5c'0xbf5c27gbk0xbf5c0x27'addslashes()

  3. $ Stmt-> निष्पादित ()

    यहां महसूस करने के लिए महत्वपूर्ण बात यह है कि डिफ़ॉल्ट रूप से पीडीओ सही तैयार बयान नहीं करता है। यह उनका (MySQL के लिए) अनुकरण करता है। इसलिए, PDO आंतरिक रूप से क्वेरी स्ट्रिंग, mysql_real_escape_string()प्रत्येक बाध्य स्ट्रिंग मान पर (MySQL C API फ़ंक्शन) कॉल करता है।

    सी एपीआई कॉल mysql_real_escape_string()इससे अलग addslashes()है कि यह कनेक्शन वर्ण सेट को जानता है। तो यह सर्वर सेट की उम्मीद कर रहे चरित्र सेट के लिए भागने का ठीक से प्रदर्शन कर सकता है। हालाँकि, इस बिंदु तक, क्लाइंट को लगता है कि हम अभी भी latin1कनेक्शन के लिए उपयोग कर रहे हैं , क्योंकि हमने इसे अन्यथा कभी नहीं बताया। हमने उस सर्वर को बताया जिसका हम उपयोग कर रहे हैं gbk, लेकिन ग्राहक अभी भी सोचता है latin1

    इसलिए कॉल mysql_real_escape_string()बैकस्लैश सम्मिलित करता है, और 'हमारी "बच गई" सामग्री में एक मुफ़्त लटका हुआ चरित्र है! वास्तव में, अगर हमें चरित्र सेट $varमें देखना था gbk, तो हम देखेंगे:

    = 'या 1 = 1 / *

    जो वास्तव में हमले की आवश्यकता है।

  4. पूछताछ

    यह हिस्सा सिर्फ एक औपचारिकता है, लेकिन यहां प्रस्तुत किया गया प्रश्न है:

    SELECT * FROM test WHERE name = '縗' OR 1=1 /*' LIMIT 1

बधाई हो, आपने पीडीओ तैयार तैयारियों का उपयोग करते हुए एक कार्यक्रम पर सफलतापूर्वक हमला किया ...

द सिंपल फिक्स

अब, यह ध्यान देने योग्य है कि आप तैयार किए गए कथनों को अक्षम करके इसे रोक सकते हैं:

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

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

सही सुधार

यहाँ समस्या यह है कि हमने mysql_set_charset()इसके बजाय C API को कॉल नहीं किया SET NAMES। यदि हमने किया, तो हम ठीक हो जाएंगे, क्योंकि हम 2006 से एक MySQL रिलीज का उपयोग कर रहे हैं।

आप पहले के एक MySQL रिलीज, तो एक प्रयोग कर रहे हैं बग में mysql_real_escape_string()मतलब है कि इस तरह के हमारे पेलोड में उन लोगों के रूप में अवैध multibyte वर्ण प्रयोजनों से बचने के लिए एक बाइट के रूप में इलाज किया गया है, भले ही ग्राहक को सही ढंग से कनेक्शन एन्कोडिंग के बारे में सूचित कर दिया गया था और इसलिए इस हमले होगा अभी भी सफल हैं। बग MySQL 4.1.20 , 5.0.22 और 5.1.11 में तय किया गया था ।

लेकिन सबसे बुरी बात यह है कि 5.3.6 तक PDOसी एपीआई को उजागर नहीं किया गया mysql_set_charset(), इसलिए पूर्व संस्करणों में यह हर संभव आदेश के लिए इस हमले को रोक नहीं सकता है! यह अब DSN पैरामीटर के रूप में सामने आया है , जिसका उपयोग इसके बजाय किया जाना चाहिए SET NAMES...

द सेविंग ग्रेस

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

वैकल्पिक रूप से, आप NO_BACKSLASH_ESCAPESSQL मोड को सक्षम कर सकते हैं , जो (अन्य चीजों के बीच) के संचालन को बदल देता है mysql_real_escape_string()। सक्षम किए गए इस मोड के साथ, 0x27इसके 0x2727बजाय प्रतिस्थापित किया जाएगा 0x5c27और इस प्रकार भागने की प्रक्रिया किसी भी असुरक्षित एन्कोडिंग में मान्य वर्ण नहीं बना सकती है जहां वे पहले मौजूद नहीं थे (यानी 0xbf27अभी भी 0xbf27आदि।) - इसलिए सर्वर अभी भी स्ट्रिंग को अस्वीकार कर देगा। । हालाँकि, एक अलग भेद्यता के लिए @ eggyal का उत्तर देखें जो इस SQL ​​मोड का उपयोग करने से उत्पन्न हो सकता है (यद्यपि पीडीओ के साथ नहीं)।

सुरक्षित उदाहरण

निम्नलिखित उदाहरण सुरक्षित हैं:

mysql_query('SET NAMES utf8');
$var = mysql_real_escape_string("\xbf\x27 OR 1=1 /*");
mysql_query("SELECT * FROM test WHERE name = '$var' LIMIT 1");

क्योंकि सर्वर की उम्मीद है utf8...

mysql_set_charset('gbk');
$var = mysql_real_escape_string("\xbf\x27 OR 1=1 /*");
mysql_query("SELECT * FROM test WHERE name = '$var' LIMIT 1");

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

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->query('SET NAMES gbk');
$stmt = $pdo->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$stmt->execute(array("\xbf\x27 OR 1=1 /*"));

क्योंकि हम तैयार बयानों का अनुकरण कर चुके हैं।

$pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=gbk', $user, $password);
$stmt = $pdo->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$stmt->execute(array("\xbf\x27 OR 1=1 /*"));

क्योंकि हमने कैरेक्टर सेट ठीक से सेट किया है।

$mysqli->query('SET NAMES gbk');
$stmt = $mysqli->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$param = "\xbf\x27 OR 1=1 /*";
$stmt->bind_param('s', $param);
$stmt->execute();

क्योंकि MySQLi हर समय सच तैयार स्टेटमेंट्स करता है।

समेट रहा हु

अगर तुम:

  • MySQL के आधुनिक संस्करणों (5.1, सभी 5.5, 5.6, आदि) और PDO के DSN चारसेट पैरामीटर (PHP SQL 5.3.6 में) का उपयोग करें

या

  • कनेक्शन एन्कोडिंग के लिए एक कमजोर वर्ण सेट का उपयोग न करें (आप केवल utf8/ latin1/ ascii/ etc का उपयोग करें )

या

  • NO_BACKSLASH_ESCAPESSQL मोड सक्षम करें

आप 100% सुरक्षित हैं।

अन्यथा, आप पीडीओ तैयार स्टेटमेंट का उपयोग करते हुए भी असुरक्षित हैं ...

परिशिष्ट

मैं धीरे-धीरे एक पैच पर काम कर रहा हूं ताकि PHP के भविष्य के संस्करण के लिए तैयारी का अनुकरण न करने के लिए डिफ़ॉल्ट को बदल सके। समस्या यह है कि मैं भाग रहा हूं कि जब मैं ऐसा करता हूं तो बहुत सारे परीक्षण टूट जाते हैं। एक समस्या यह है कि उत्सर्जित तैयारी केवल निष्पादन पर वाक्यविन्यास त्रुटियों को फेंक देगी, लेकिन सच्ची तैयारी त्रुटियों को तैयारी पर फेंक देगी। ताकि समस्याएँ पैदा हो सकें (और कारण यह है कि परीक्षण बोरिंग हैं)।


47
यह सबसे अच्छा जवाब है जो मैंने पाया है .. क्या आप अधिक संदर्भ के लिए एक लिंक प्रदान कर सकते हैं?
स्टेटिक वियरेबल सेप

1
@nicogawenda: यह एक अलग बग था। 5.0.22 से पहले, mysql_real_escape_stringउन मामलों को ठीक से नहीं संभालेंगे जहां कनेक्शन BIG5 / GBK पर ठीक से सेट किया गया था। तो वास्तव में भी mysql_set_charset()mysql <5.0.22 पर कॉल करना इस बग के लिए असुरक्षित होगा! तो नहीं, यह पोस्ट अभी भी 5.0.22 पर लागू है (क्योंकि mysql_real_escape_string केवल कॉल करने के लिए दूर है mysql_set_charset(), जो इस पोस्ट को बायपास करने की बात कर रहा है) ...
ircmaxell

1
@progfa यह करता है या नहीं, आपको उपयोगकर्ता डेटा के साथ कुछ भी करने से पहले सर्वर पर अपने इनपुट को हमेशा मान्य करना चाहिए।
टेक

2
कृपया ध्यान दें कि NO_BACKSLASH_ESCAPESनई कमजोरियाँ भी पेश कर सकते हैं: stackoverflow.com/a/23277864/1014813
lepix

2
@slevin "OR 1 = 1" जो आप चाहते हैं उसके लिए प्लेसहोल्डर है। हां, यह नाम में एक मूल्य खोज रहा है, लेकिन "OR 1 = 1" भाग की कल्पना "उपयोगकर्ता का चयन करें" से किया गया था। अब आप क्वेरी को नियंत्रित करते हैं, और इस तरह से इसका दुरुपयोग कर सकते हैं ...
ircmaxell

515

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

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

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

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

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

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


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


6
यह तो दिलचस्प है। मुझे 1 आदेश बनाम 2 वें आदेश के बारे में पता नहीं था। क्या आप इस बारे में थोड़ा विस्तार कर सकते हैं कि 2nd ऑर्डर कैसे काम करता है?
मार्क बीओपी

193
यदि आपके सभी प्रश्न पैराट्राइज्ड हैं, तो आप 2nd ऑर्डर इंजेक्शन से भी सुरक्षित हैं। 1st ऑर्डर इंजेक्शन यह भूल रहा है कि उपयोगकर्ता डेटा अविश्वसनीय है। दूसरा आदेश इंजेक्शन यह भूल रहा है कि डेटाबेस डेटा अविश्वसनीय है (क्योंकि यह मूल रूप से उपयोगकर्ता से आया था)।
cjm

6
धन्यवाद cjm : मैं भी इस लेख 2 क्रम इंजेक्शन समझाने में उपयोगी पाया codeproject.com/KB/database/SqlInjectionAttacks.aspx
मार्क Biek

49
आह येस। लेकिन तीसरे क्रम के इंजेक्शन के बारे में क्या । उन के बारे में पता होना चाहिए।
troelskn

81
@troelskn जो डेवलपर को अविश्वसनीय डेटा का स्रोत होना चाहिए
माइकमैर्को

45

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

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

$dbh = new PDO("blahblah");

$tableToUse = $_GET['userTable'];

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

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

$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 नहीं हैं । पीडीओ केवल डेटा के लिए बच सकता है । दूसरे, आप इसके चारों ओर उद्धरण भी नहीं डाल सकते । उपयोगकर्ता को छांटने की अनुमति देने का एकमात्र तरीका मैन्युअल रूप से फ़िल्टर करना और जांचना है कि यह या तो है ।'DESCASC


11
क्या मुझे यहाँ कुछ याद आ रहा है लेकिन एक स्ट्रिंग की तरह sql के इलाज से बचने के लिए तैयार किए गए कथनों की पूरी बात नहीं है? $ Dbh-> तैयार ('चयन * से: tableToUse जहां उपयोगकर्ता नाम: उपयोगकर्ता नाम'); अपनी समस्या के आसपास?
रॉब फॉरेस्ट

4
@RobForrest हाँ आप याद कर रहे हैं :)। आपके द्वारा बाँधा गया डेटा केवल DDL (डेटा परिभाषा भाषा) के लिए काम करता है। आपको उन उद्धरणों और उचित भागने की आवश्यकता है। क्वेरी के अन्य भागों के लिए उद्धरण रखने से यह उच्च संभावना के साथ टूट जाता है। उदाहरण के लिए, SELECT * FROM 'table'गलत हो सकता है जैसा कि यह होना चाहिए SELECT * FROM `table`या बिना किसी बैकस्ट के होना चाहिए । फिर जैसे कुछ बातें ORDER BY DESCजहां DESCउपयोगकर्ता से आता है बस का उपयोग नहीं किया जा सकता है। इसलिए, व्यावहारिक परिदृश्य असीमित हैं।
टॉवर

8
मुझे आश्चर्य है कि 6 लोग एक टिप्पणी को तैयार कथन के स्पष्ट रूप से गलत उपयोग का प्रस्ताव कैसे दे सकते हैं। अगर उन्होंने एक बार भी कोशिश की, तो उन्हें तुरंत पता चल गया कि टेबल नाम के स्थान पर नामित पैरामीटर का उपयोग करने से काम नहीं चलेगा।
फेलिक्स गगनोन-ग्रेनियर

यदि आप इसे सीखना चाहते हैं तो पीडीओ पर एक बढ़िया ट्यूटोरियल है। a2znotes.blogspot.in/2014/09/introduction-to-pdo.html
आरएन कुशवाहा

11
उपयोग करने के लिए तालिका लेने के लिए आपको कभी भी क्वेरी स्ट्रिंग / POST बॉडी का उपयोग नहीं करना चाहिए। यदि आपके पास मॉडल नहीं हैं, switchतो तालिका के नाम को प्राप्त करने के लिए कम से कम एक का उपयोग करें।
जिग्गीमॉन्थ

29

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

Parameterised क्वेरीज़ कोड और डेटा को अलग-अलग भेजकर काम करती हैं, इसलिए इसमें छेद ढूंढना संभव नहीं होगा ।

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


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

29

नहीं, यह पर्याप्त नहीं है (कुछ विशिष्ट मामलों में)! डेटाबेस ड्राइवर के रूप में 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 में SQL इंजेक्शन को कैसे रोक सकता हूं?

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


14

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


1

Eaven यदि आप html या js चेक्स का उपयोग करते हुए sql injection front-end को रोकने जा रहे हैं, तो आपको विचार करना होगा कि front-end चेक "bypassable" हैं।

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

इसलिए, SQL इंजेक्शन को रोकने के लिए, अपने कंट्रोलर के अंदर इनपुट डेट बैकएंड को सैनिटाइज करना सही होगा।

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

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

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

आसान उदाहरण:

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

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

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


5
आप SQL इंजेक्शन को किसी और चीज़ के साथ भ्रमित कर रहे हैं जो आपके उत्तर को पूरी तरह अप्रासंगिक बनाता है
आपका कॉमन सेंस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.