SQL Injection ऐप्लिकेशन डेटाबेस पर हमले का एक प्रकार है, जिसमें हमलावर क्वेरी पैरामीटर में दुर्भावनापूर्ण SQL कोड इंजेक्ट करता है, जिससे डेटा तक अनधिकृत पहुँच या उनमें संशोधन की क्षमता प्राप्त होती है। OWASP (2025) के अनुसार, SQL Injection एक गंभीर कमजोरी बनी हुई है जो डेटाबेस से पूरी तरह समझौता कर सकती है। SQL कोड इंजेक्शन हमलावर को रिकॉर्ड पढ़ने, बदलने और हटाने की अनुमति देता है, और कुछ मामलों में, सर्वर के ऑपरेटिंग सिस्टम तक पहुँच प्राप्त करने की भी।
मुख्य बिंदु
SQL Injection एक कमजोरी है जो तब उत्पन्न होती है जब कोई ऐप्लिकेशन उपयोगकर्ता डेटा के साथ स्ट्रिंग कॉन्केटनेशन द्वारा SQL क्वेरी बनाता है। हमलावर क्वेरी पैरामीटर में एक विशेष रूप से तैयार स्ट्रिंग पास करता है जो SQL कमांड की संरचना को बदल देती है। डेटा होने के बजाय, इंजेक्ट की गई स्ट्रिंग SQL कोड का हिस्सा बन जाती है, जिससे हमलावर डेटाबेस पर मनमानी क्वेरी निष्पादित कर सकता है। Verizon डेटा उल्लंघन रिपोर्ट (2025) के अनुसार, SQL Injection सभी जांचे गए डेटा उल्लंघनों में 8% में मौजूद है।
एक ज्ञात कमजोरी होने के बावजूद (पहली बार 1990 के दशक के अंत में उल्लेखित), SQL Injection आधुनिक ऐप्लिकेशन में अभी भी पाया जाता है। इसका कारण मानवीय त्रुटि है: डेवलपर स्ट्रिंग कॉन्केटनेशन वाला कोड लिखते हैं, लीगेसी कोड रीफैक्टर नहीं किया जाता, और ORM फ्रेमवर्क का गलत उपयोग किया जाता है (जैसे, स्ट्रिंग इंटरपोलेशन वाली raw क्वेरी)। Veracode (2026) के अनुसार, सभी स्कैन किए गए ऐप्लिकेशन में से लगभग 14% में कम से कम एक SQLi कमजोरी होती है।
एक सफल SQL Injection हमलावर को व्यापक क्षमताएँ देता है: पासवर्ड हैश और उपयोगकर्ताओं के व्यक्तिगत डेटा सहित किसी भी डेटाबेस तालिका को पढ़ना; रिकॉर्ड को संशोधित और हटाना; प्रशासनिक संचालन निष्पादित करना (DROP TABLE, TRUNCATE); और कुछ कॉन्फ़िगरेशन में, xp_cmdshell (MSSQL) या INTO OUTFILE (MySQL) के माध्यम से दूरस्थ कमांड निष्पादन। परिणाम उपयोगकर्ता डेटा लीक से लेकर सिस्टम पर पूर्ण नियंत्रण खोने तक होते हैं।
SQL इंजेक्शन को डेटाबेस से डेटा निकालने के तरीके के आधार पर वर्गीकृत किया जाता है। विधि का चुनाव इस बात पर निर्भर करता है कि ऐप्लिकेशन क्वेरी परिणामों और त्रुटि संदेशों को कैसे संभालता है। OWASP वर्गीकरण तीन मुख्य प्रकारों की पहचान करता है: In-band (उसी चैनल के माध्यम से डेटा निकालना), Inferential/Blind (तार्किक अनुमान), और Out-of-band (दूसरे चैनल के माध्यम से डेटा संचारित करना)।
| प्रकार | डेटा निष्कर्षण विधि | जटिलता | आवृत्ति |
|---|---|---|---|
| In-band (क्लासिक) | सीधे क्वेरी परिणाम के माध्यम से | कम | उच्च |
| Blind SQLi | सर्वर प्रतिक्रियाओं से तार्किक अनुमान | उच्च | मध्यम |
| Out-of-band | बाहरी चैनल (DNS, HTTP) के माध्यम से | मध्यम | कम |
सबसे सामान्य प्रकार। हमलावर क्वेरी पैरामीटर में SQL कोड इंजेक्ट करता है, और इंजेक्शन का परिणाम सीधे सर्वर प्रतिक्रिया में दिखाई देता है। दो उपप्रकार: Error-based (DB त्रुटि संदेशों के माध्यम से) और UNION-based (UNION SELECT ऑपरेटर के माध्यम से)। Error-based त्रुटि संदेशों से जानकारी का उपयोग करता है, जैसे MySQL सिंटैक्स त्रुटि जो तालिका का नाम या क्वेरी संरचना प्रकट कर सकती है। UNION-based वैध क्वेरी के परिणामों को डेटाबेस की अन्य तालिकाओं के डेटा के साथ संयोजित करने की अनुमति देता है।
तब उपयोग किया जाता है जब ऐप्लिकेशन क्वेरी परिणाम या त्रुटि संदेश प्रदर्शित नहीं करता है। हमलावर तार्किक शर्तों वाली क्वेरी भेजकर और सर्वर प्रतिक्रियाओं (जैसे, प्रतिक्रिया समय या पृष्ठ सामग्री) में अंतर का विश्लेषण करके हाँ/नहीं प्रश्न पूछता है। Time-based Blind SQLi शर्तों की पुष्टि करने के लिए विलंब फ़ंक्शन (SLEEP, WAITFOR DELAY) का उपयोग करता है — यदि पृष्ठ लोड होने में अधिक समय लेता है, तो शर्त सत्य है। यह विधि बहुत धीमी है — एक रिकॉर्ड निकालने में घंटों लग सकते हैं।
# Blind SQL Injection का उदाहरण (समय-आधारित)
# यदि SQLi कमजोर है, SLEEP(2) शर्त पूरी होने पर निष्पादित होता है
import requests
import time
payload = "' OR IF(SUBSTRING((SELECT password FROM users LIMIT 1),1,1)='a',SLEEP(2),0) -- "
url = "http://example.com/user?id=1" + payload
start = time.time()
response = requests.get(url)
elapsed = time.time() - start
# यदि प्रतिक्रिया >2 सेकंड के बाद आती है — पासवर्ड का पहला अक्षर 'a' है
print(f"Time: {elapsed:.2f}s - First letter is 'a'" if elapsed > 2 else "First letter is not 'a'")
डेटा HTTP प्रतिक्रिया के माध्यम से नहीं बल्कि वैकल्पिक चैनलों के माध्यम से प्रेषित किया जाता है: DNS क्वेरी, बाहरी सर्वर पर HTTP अनुरोध, SMTP। तब उपयोग किया जाता है जब ऐप्लिकेशन क्वेरी परिणाम वापस नहीं करता है या त्रुटियाँ नहीं दिखाता है। MySQL LOAD_FILE() फ़ंक्शन का समर्थन करता है, जो DNS अनुरोध शुरू कर सकता है, और MSSQL में दूरस्थ SMB सर्वर पर डेटा भेजने के लिए xp_dirtree है। Out-of-band SQL Injection प्रभावी है लेकिन इसके लिए अतिरिक्त हमलावर सर्वर सेटअप और विशिष्ट DB फ़ंक्शन की आवश्यकता होती है।
SQL Injection तंत्र इस तथ्य पर आधारित है कि SQL स्ट्रिंग लिटरल के लिए उद्धरण का उपयोग करता है। यदि कोई ऐप्लिकेशन उपयोगकर्ता इनपुट को बिना एस्केप किए सीधे SQL क्वेरी में डालता है, तो हमलावर स्ट्रिंग को “बंद” कर सकता है और मनमाना SQL कोड जोड़ सकता है। उदाहरण के लिए, क्वेरी SELECT * FROM users WHERE name = '$input' में, ' OR '1'='1 डालने से यह SELECT * FROM users WHERE name = '' OR '1'='1' में बदल जाती है, जो सभी उपयोगकर्ताओं को लौटाती है।
क्वेरी SELECT * FROM users WHERE username = '$user' AND password = '$pass' वाले लॉगिन फ़ॉर्म पर विचार करें। यदि हमलावर उपयोगकर्ता नाम फ़ील्ड में admin' -- दर्ज करता है और पासवर्ड खाली छोड़ देता है, तो परिणामी क्वेरी SELECT * FROM users WHERE username = 'admin' -- ' AND password = '' बन जाती है। -- वर्ण शेष क्वेरी को कमेंट कर देते हैं, पासवर्ड जाँच को अक्षम कर देते हैं। सर्वर admin उपयोगकर्ता रिकॉर्ड लौटाता है, और हमलावर पासवर्ड जाने बिना लॉग इन कर लेता है।
# SQL Injection का उदाहरण — प्रमाणीकरण बायपास
# कमजोर कोड: प्रत्यक्ष स्ट्रिंग कॉन्केटनेशन
def login_vulnerable(username, password):
query = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'"
cursor.execute(query)
return cursor.fetchone() is not None
# username = "admin' --" पासवर्ड जाँच को रद्द करता है
# सुरक्षित संस्करण: पैरामीटराइज़्ड क्वेरी
def login_secure(username, password):
query = "SELECT * FROM users WHERE username = %s AND password = %s"
cursor.execute(query, (username, password))
return cursor.fetchone() is not None
UNION SELECT ऑपरेटर दो SELECT क्वेरी के परिणामों को संयोजित करने की अनुमति देता है। यदि हमलावर को कोई कमजोर पैरामीटर मिलता है, तो वह दूसरी तालिका से क्वेरी के साथ UNION SELECT जोड़ता है। उदाहरण: ' UNION SELECT username, password FROM admins --. सफलता की शर्त यह है कि दोनों क्वेरी में कॉलम की संख्या समान होनी चाहिए। कॉलम की संख्या ORDER BY के माध्यम से निर्धारित की जाती है (' ORDER BY 1--, फिर 2, 3... त्रुटि होने तक)। कॉलम की संख्या जानकर, हमलावर समान संख्या में फ़ील्ड के साथ UNION SELECT डालता है।
मोबाइल ऐप्लिकेशन सर्वर साइड (API) और क्लाइंट साइड — स्थानीय डेटाबेस (SQLite, Realm) दोनों पर SQL Injection का सामना करते हैं। जबकि मोबाइल API में सर्वर-साइड SQLi वेब ऐप्लिकेशन के समान है, स्थानीय डेटाबेस एक अतिरिक्त वेक्टर बनाते हैं। यदि कोई ऐप्लिकेशन SQLite में डेटा संग्रहीत करता है और स्ट्रिंग कॉन्केटनेशन के साथ क्वेरी निष्पादित करता है, तो API के माध्यम से स्थानीय डेटाबेस में प्रवेश करने वाला दुर्भावनापूर्ण डेटा बाद की प्रक्रिया के दौरान SQLi को ट्रिगर कर सकता है।
डिवाइस पर स्थानीय SQLite डेटाबेस भी SQL Injection के लिए कमजोर है यदि ऐप्लिकेशन स्ट्रिंग कॉन्केटनेशन द्वारा क्वेरी बनाता है। Android पर Content Providers और iOS पर Core Data डिफ़ॉल्ट रूप से पैरामीटराइज़ेशन का उपयोग करते हैं, लेकिन raw क्वेरी के लिए डेवलपर के ध्यान की आवश्यकता होती है। SQLite सेमीकोलन द्वारा अलग की गई एकाधिक क्वेरी का समर्थन नहीं करता है, जो हमलावर के विकल्पों को सीमित करता है लेकिन WHERE शर्तों के माध्यम से डेटा पढ़ने से नहीं बचाता है। Android में हमेशा selectionArgs और iOS में पैरामीटर के साथ NSPredicate का उपयोग करें।
जिस API से मोबाइल ऐप्लिकेशन संचार करता है, वह किसी भी वेब सर्वर की तरह ही कमजोर है। मोबाइल डेवलपर अक्सर मानते हैं कि SQLi केवल बैकएंड की समस्या है, लेकिन कमजोरी API एंडपॉइंट पर होती है जो क्लाइंट से पैरामीटर स्वीकार करता है। जिम्मेदारियों का पृथक्करण सुरक्षा नहीं करता है: यदि बैकएंड डेवलपर क्वेरी को पैरामीटराइज़ करना भूल गया, तो उपयोगकर्ता का मोबाइल ऐप हमले का वेक्टर बन जाता है। बैकएंड से ORM या prepared statements का उपयोग करने की अपेक्षा करें।
// Android पर स्थानीय SQLite में SQL Injection का उदाहरण
// कमजोर कोड: प्रत्यक्ष कॉन्केटनेशन
fun getUserVulnerable(db: SQLiteDatabase, userId: String): Cursor {
return db.rawQuery(
"SELECT * FROM users WHERE id = $userId", null
)
}
// सुरक्षित संस्करण: selectionArgs के माध्यम से पैरामीटराइज़ेशन
fun getUserSecure(db: SQLiteDatabase, userId: String): Cursor {
return db.rawQuery(
"SELECT * FROM users WHERE id = ?",
arrayOf(userId)
)
}
SQL Injection से सुरक्षा एक सरल सिद्धांत पर आधारित है: SQL क्वेरी में उपयोगकर्ता इनपुट पर कभी भरोसा न करें। एकमात्र विश्वसनीय तरीका क्वेरी पैरामीटराइज़ेशन (prepared statements) है, जहाँ SQL कोड और डेटा अलग-अलग पास किए जाते हैं। अन्य सभी विधियाँ — एस्केपिंग, वैलिडेशन, WAF — अतिरिक्त सुरक्षा परतें हैं लेकिन पैरामीटराइज़ेशन को प्रतिस्थापित नहीं करती हैं। OWASP (2025) के अनुसार, पैरामीटराइज़ेशन 100% SQL Injection हमलों को रोकता है।
Prepared statements का उपयोग करते समय, SQL क्वेरी पहले DB सर्वर द्वारा डेटा के बिना संकलित की जाती है, और फिर पैरामीटर मान अलग-अलग पास किए जाते हैं। डेटाबेस पैरामीटर को डेटा के रूप में मानता है, निष्पादन योग्य कोड के रूप में नहीं। भले ही हमलावर ' OR '1'='1 पास करे, डेटाबेस इसे SQL कोड के रूप में नहीं बल्कि एक स्ट्रिंग मान के रूप में व्याख्यायित करता है। Prepared statements सभी आधुनिक भाषाओं और फ्रेमवर्क द्वारा समर्थित हैं: PHP में PDO, Java में PreparedStatement, Python में cursor.execute।
आधुनिक ORM (Hibernate, Entity Framework, SQLAlchemy, Room) क्वेरी निष्पादित करते समय स्वचालित रूप से पैरामीटराइज़ेशन का उपयोग करते हैं, जब तक कि डेवलपर raw क्वेरी पर स्विच नहीं करता है। हालाँकि, ORM पूरी तरह से सुरक्षा नहीं करते हैं: JPA में @Query(value = "SELECT * FROM users WHERE name = :name", nativeQuery = true) जैसी संरचनाओं के लिए नामित पैरामीटर के माध्यम से पैरामीटर पास करने की आवश्यकता होती है, कॉन्केटनेशन नहीं। क्वेरी बिल्डर (Knex, jOOQ) भी डिफ़ॉल्ट रूप से क्वेरी को पैरामीटराइज़ करते हैं यदि raw विधियों का उपयोग नहीं किया जाता है।
विशेष वर्णों को एस्केप करना (mysql_real_escape_string) एक पुरानी विधि है जो सभी प्रकार के SQL Injection से सुरक्षा नहीं करती है। समस्या: एस्केपिंग एन्कोडिंग पर निर्भर करती है और मल्टी-बाइट एन्कोडिंग (जैसे, एशियाई सिस्टम में GBK) का उपयोग करते समय इसे बायपास किया जा सकता है। केवल लीगेसी कोड में एस्केपिंग का उपयोग करें जहाँ पैरामीटराइज़ेशन संभव नहीं है, और हमेशा सख्त इनपुट टाइप वैलिडेशन के साथ संयोजन में।
| विधि | प्रभावशीलता | अनुशंसा |
|---|---|---|
| Prepared Statements | 100% | सभी क्वेरी के लिए अनिवार्य |
| ORM (सही उपयोग) | 99% | अनुशंसित |
| स्ट्रिंग एस्केपिंग | 70% (एन्कोडिंग पर निर्भर) | केवल लीगेसी |
| इनपुट वैलिडेशन (white-list) | 50% (केवल संख्याएँ) | अतिरिक्त |
| WAF (Web Application Firewall) | 60% | अतिरिक्त |
एप्लिकेशन खाते में न्यूनतम आवश्यक विशेषाधिकार होने चाहिए: SELECT, INSERT, UPDATE, DELETE — केवल उन तालिकाओं पर जिनकी एप्लिकेशन को वास्तव में आवश्यकता है। एप्लिकेशन खाते के लिए DROP, TRUNCATE, CREATE के उपयोग पर रोक लगाएँ। यह सफल SQL Injection की स्थिति में भी नुकसान को सीमित करता है: हमलावर तालिकाओं को हटा नहीं पाएगा या प्रशासनिक संचालन निष्पादित नहीं कर पाएगा।
नियमित SQL Injection परीक्षण सुरक्षित विकास पाइपलाइन का हिस्सा होना चाहिए। स्थैतिक विश्लेषण, गतिशील स्कैनिंग और मैन्युअल पेनिट्रेशन परीक्षण का संयोजन सबसे अच्छे परिणाम देता है। Synopsys साइबर सिक्योरिटी रिपोर्ट (2025) के अनुसार, स्वचालित स्कैनर 70% तक SQLi कमजोरियाँ ढूँढ लेते हैं, लेकिन जटिल Blind हमलों के लिए मैन्युअल परीक्षण की आवश्यकता होती है।
मोबाइल एप्लिकेशन के लिए, स्थानीय SQLite विश्लेषण भी महत्वपूर्ण है: सभी rawQuery कॉल, ContentProvider क्वेरी और rawQuery वाली Room क्वेरी की जाँच करें। उपकरण: Android Studio Lint (SQLite में SQLi का पता लगाता है), APK/IPA के स्वचालित स्थैतिक और गतिशील विश्लेषण के लिए MobSF (Mobile Security Framework)। मोबाइल एप्लिकेशन के ट्रैफ़िक के प्रॉक्सी इंटरसेप्शन के साथ sqlmap के माध्यम से API एंडपॉइंट का परीक्षण करने की भी सिफारिश की जाती है।
अक्सर पूछे जाने वाले प्रश्न
SQL Injection SQL क्वेरी के माध्यम से रिलेशनल डेटाबेस पर हमला करता है। NoSQL Injection उनके क्वेरी ऑपरेटरों ($gte, $ne, $where) के माध्यम से नॉन-रिलेशनल डेटाबेस (MongoDB, Couchbase) को प्रभावित करता है। MongoDB में, इंजेक्शन संभव है यदि एप्लिकेशन JSON स्ट्रिंग से BSON दस्तावेज़ बनाता है। सुरक्षा तंत्र समान हैं: पैरामीटराइज़ेशन और टाइप वैलिडेशन।
उन सभी स्थानों को खोजें जहाँ SQL क्वेरी उपयोगकर्ता डेटा के साथ स्ट्रिंग कॉन्केटनेशन द्वारा बनाई जाती हैं। "SELECT ... WHERE id = " + userId या f"UPDATE ... SET name = '{name}'" जैसे पैटर्न देखें। ऐसी प्रत्येक पंक्ति एक संभावित SQL इंजेक्शन है। उन सभी को पैरामीटराइज़्ड क्वेरी या prepared statements से बदलें।
ORM फ्रेमवर्क केवल तभी स्वचालित रूप से सुरक्षा करते हैं जब आप उनके क्वेरी बिल्डर विधियों और नामित पैरामीटर का उपयोग करते हैं। यदि आप raw क्वेरी (JPA में nativeQuery, Room में rawQuery) का उपयोग करते हैं, तो सुरक्षा काम नहीं करती है — आपको स्ट्रिंग कॉन्केटनेशन के माध्यम से नहीं बल्कि तैयार अभिव्यक्तियों के माध्यम से पैरामीटर पास करने होंगे।
सेकंड-ऑर्डर SQL Injection एक हमला है जहाँ दुर्भावनापूर्ण डेटा डेटाबेस में सुरक्षित रूप से संग्रहीत किया जाता है, लेकिन फिर बिना एस्केपिंग के किसी अन्य क्वेरी में उपयोग किया जाता है। उदाहरण के लिए, एक हमलावर ' OR '1'='1 जैसे उपयोगकर्ता नाम से पंजीकरण करता है। डेटा एक स्ट्रिंग के रूप में सहेजा जाता है — पंजीकरण पर कोई हमला नहीं होता है। लेकिन यदि कोई अन्य क्वेरी बिना पैरामीटराइज़ेशन के SQL में उपयोगकर्ता नाम का उपयोग करती है, तो इंजेक्शन सक्रिय हो जाता है।
NoSQL Injection कम डेवलपर जागरूकता के कारण संभावित रूप से अधिक खतरनाक हो सकता है। डेवलपर SQL Injection के बारे में जानते हैं और अधिकांश ORM का उपयोग करते हैं, लेकिन कुछ ही NoSQL Injection के बारे में जानते हैं। MongoDB में, अनुचित रूप से बनाई गई क्वेरी संग्रह के सभी दस्तावेज़ लौटा सकती है। सुरक्षा वही है — prepared statements (BSON पैरामीटराइज़ेशन) और सख्त इनपुट वैलिडेशन।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें