SQL injection और mysql_real_escape_string() का सच: मिथक और वास्तविकता

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

परिचय: क्या mysql_real_escape_string() पर भरोसा करना सही है?

\n\n

आपने PHP डेवलपर्स की एक पुरानी कहावत सुनी होगी: "mysql_real_escape_string() सभी SQL-इंजेक्शन से बचाता है"। क्या यह सच है? 2024 में, जब PDO और prepared statements मानक बन चुके हैं, यह विषय पुराना लग सकता है। लेकिन हजारों डेवलपर आज भी पुराने प्रोजेक्ट्स को संभाल रहे हैं, जहाँ mysql_real_escape_string() ही सुरक्षा की एकमात्र दीवार है।

\n\n

Stack Overflow पर सवाल "SQL injection that gets around mysql_real_escape_string()" ने लाखों व्यूज बटोरे हैं। क्यों? क्योंकि इसका जवाब आसान नहीं है। इस लेख में हम उन असली स्थितियों को समझेंगे जहाँ यह फंक्शन फेल हो जाता है, और सुरक्षा के अलग-अलग तरीकों की तुलना करेंगे। अगर आप PHP में कोड लिखते हैं, तो ध्यान से पढ़ें।

\n\n

mysql_real_escape_string() कैसे काम करता है

\n\n

फंक्शन mysql_real_escape_string() (जो mysql_* एक्सटेंशन का हिस्सा है, अब deprecated) कनेक्शन की मौजूदा एन्कोडिंग के अनुसार स्पेशल कैरेक्टर्स को एस्केप करता है। यह कैरेक्टर्स ', ", \\, \\n, \\r, NULL और Control-Z के आगे बैकस्लैश जोड़ता है।

\n\n
<?php\n$connection = mysql_connect('localhost', 'user', 'pass');\nmysql_select_db('test', $connection);\n$unsafe = "O'Brien";\n$safe = mysql_real_escape_string($unsafe); // O\\'Brien\n$query = "SELECT * FROM users WHERE name = '$safe'";\n?>
\n\n

लगता है यह काम कर रहा है। लेकिन कुछ पेचीदा बातें हैं।

\n\n

परिदृश्य 1: एन्कोडिंग की समस्या (GBK / Big5)

\n\n

सबसे मशहूर बायपास तरीका है मल्टीबाइट एन्कोडिंग का उपयोग, जैसे GBK (चीनी) या Big5। अगर कनेक्शन GBK में सेट है और आप %bf%27 स्ट्रिंग भेजते हैं, तो जादू होता है।

\n\n

GBK में बाइट 0xbf एक पूरा कैरेक्टर नहीं है। जब mysql_real_escape_string() को ' (0x27) मिलता है, तो यह बैकस्लैश 0x5c जोड़ता है। परिणामी सीक्वेंस होता है: 0xbf + 0x5c + 0x27। लेकिन GBK में 0xbf5c एक वैध कैरेक्टर है (जैसे चीनी अक्षर "縗")। इसका मतलब बैकस्लैश "खत्म" हो जाता है, और क्वोट बिना सुरक्षा के रह जाता है!

\n\n
<?php\n// GBK एन्कोडिंग सेट करना\nmysql_query("SET NAMES 'GBK'", $connection);\n$input = "%bf%27"; // बाइट्स: 0xbf 0x27\n$escaped = mysql_real_escape_string($input, $connection);\n// परिणाम: 0xbf5c27 -> GBK में यह "縗'" है (क्वोट बच गया)\n$query = "SELECT * FROM users WHERE id = '$escaped'";\n// असल में चलेगा: SELECT * FROM users WHERE id = '縗''\n// अब इंजेक्ट कर सकते हैं: ' OR 1=1 -- \n?>
\n\n

निष्कर्ष: अगर कनेक्शन की एन्कोडिंग डेटा की एन्कोडिंग से मेल नहीं खाती, तो mysql_real_escape_string() को बायपास किया जा सकता है। यही बग PHP बग रिपोर्ट #47168 में बताया गया था।

\n\n

परिदृश्य 2: न्यूमेरिक फील्ड का उपयोग

\n\n

एस्केपिंग सिर्फ स्ट्रिंग्स के लिए काम करता है। अगर आप बिना क्वोट्स के न्यूमेरिक फील्ड में डेटा डालते हैं, तो mysql_real_escape_string() बेकार है, क्योंकि वैल्यू एस्केप नहीं होती — यह जस की तस डाल दी जाती है।

\n\n
<?php\n$id = mysql_real_escape_string($_GET['id']); // मान लें "1 OR 1=1"\n$query = "SELECT * FROM users WHERE id = $id"; // बिना क्वोट्स!\n// खतरा: SELECT * FROM users WHERE id = 1 OR 1=1\n?>
\n\n

भले ही आप स्ट्रिंग को एस्केप कर दें, न्यूमेरिक कॉन्टेक्स्ट में इसका कोई मतलब नहीं — क्वोट्स नहीं हैं, इसलिए कोई भी SQL कोड डाला जा सकता है।

\n\n

निष्कर्ष: एस्केपिंग डेटा टाइप चेक करने का विकल्प नहीं है। नंबर्स के लिए intval() या ctype_digit() का उपयोग करें।

\n\n

परिदृश्य 3: LIKE क्वेरी और वाइल्डकार्ड कैरेक्टर

\n\n

mysql_real_escape_string() ' और \\ को एस्केप करता है, लेकिन % और _ जैसे वाइल्डकार्ड कैरेक्टर्स को नहीं छूता। LIKE क्वेरी में ये कैरेक्टर खास मायने रखते हैं।

\n\n
<?php\n$search = mysql_real_escape_string($_GET['search']); // मान लें "%; DROP TABLE users; --"\n$query = "SELECT * FROM products WHERE name LIKE '%$search%'";\n// खतरा: SELECT * FROM products WHERE name LIKE '%%; DROP TABLE users; --%'\n?>
\n\n

हालाँकि यह सीधा SQL इंजेक्शन नहीं है, लेकिन यह डेटा लीक या अनचाहे ऑपरेशन का कारण बन सकता है।

\n\n

निष्कर्ष: LIKE क्वेरी में वाइल्डकार्ड कैरेक्टर्स को मैन्युअली एस्केप करें या addcslashes() का उपयोग करें।

\n\n

सही समाधान: PDO और Prepared Statements

\n\n

इन सभी समस्याओं का सबसे अच्छा हल है PDO (PHP Data Objects) और prepared statements का उपयोग करना। यह तरीका SQL क्वेरी और डेटा को पूरी तरह अलग रखता है, जिससे इंजेक्शन असंभव हो जाता है।

\n\n
<?php\n$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');\n$stmt = $pdo->prepare('SELECT * FROM users WHERE name = :name');\n$stmt->execute(['name' => "O'Brien"]);\n// सुरक्षित! कोई एस्केपिंग की जरूरत नहीं\n?>
\n\n

PDO न सिर्फ एन्कोडिंग समस्याओं से बचाता है, बल्कि न्यूमेरिक फील्ड और LIKE क्वेरी में भी सुरक्षित है। इसके अलावा, यह कोड को ज्यादा साफ और मेंटेन करने योग्य बनाता है।

\n\n

निष्कर्ष: क्या mysql_real_escape_string() बेकार है?

\n\n

पूरी तरह से नहीं। सही परिस्थितियों में (सही एन्कोडिंग, स्ट्रिंग फील्ड, कोई वाइल्डकार्ड नहीं) यह काम करता है। लेकिन आधुनिक PHP में इस पर निर्भर रहना जोखिम भरा है।

\n\n

हमारी सलाह: नए प्रोजेक्ट्स में हमेशा PDO और prepared statements का उपयोग करें। पुराने प्रोजेक्ट्स को माइग्रेट करें। याद रखें: सुरक्षा कोई शॉर्टकट नहीं है — सही टूल का उपयोग करें।

\n\n

अगर आपको यह लेख उपयोगी लगा, तो इसे अपने डेवलपर दोस्तों के साथ शेयर करें और टिप्पणी में बताएं कि आप SQL injection से बचाव के लिए क्या उपाय करते हैं!

ब्लॉग

पुस्तक अनुशंसाएँ