यह कोड ठीक से काम करता है क्योंकि यह है:
- परिमाणित, और
- कोई डायनेमिक एसक्यूएल नहीं कर रहा
काम करने के लिए SQL इंजेक्शन के लिए आदेश में, आप एक क्वेरी स्ट्रिंग निर्माण करने के लिए (जो आप कर नहीं कर रहे हैं) और राशि नहीं का अनुवाद एकल अक्षर लोप ( '
) भाग निकले-अक्षर लोप में ( ''
) (उन इनपुट पैरामीटर के माध्यम से भाग निकले हैं)।
"समझौता" मूल्य में पारित करने के आपके प्रयास में, 'Male; DROP TABLE tblActor'
स्ट्रिंग केवल एक सादा-ओल 'स्ट्रिंग है।
अब, यदि आप की तर्ज पर कुछ कर रहे हैं:
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'SELECT fields FROM table WHERE field23 = '
+ @InputParam;
EXEC(@SQL);
तब यह SQL इंजेक्शन के लिए अतिसंवेदनशील होगा क्योंकि यह क्वेरी वर्तमान, पूर्व-पार्स संदर्भ में नहीं है; वह क्वेरी फिलहाल एक और स्ट्रिंग है। तो मान @InputParam
हो सकता है '2015-10-31'; SELECT * FROM PlainTextCreditCardInfo;
और यह एक समस्या पेश कर सकता है क्योंकि उस क्वेरी का प्रतिपादन किया जाएगा, और निष्पादित किया जाएगा, जैसे:
SELECT fields FROM table WHERE field23 = '2015-10-31'; SELECT * FROM PlainTextCreditCardInfo;
संग्रहीत प्रक्रियाओं का उपयोग करने का यह एक (कई) प्रमुख कारण है: स्वाभाविक रूप से अधिक सुरक्षित (ठीक है, जब तक कि आप उन प्रश्नों को बनाकर उस सुरक्षा को दरकिनार नहीं करते हैं जैसे कि मैंने ऊपर दिखाए गए किसी भी पैरामीटर के मूल्यों को मान्य किए बिना दिखाया है)। हालाँकि यदि आपको डायनेमिक SQL बनाने की आवश्यकता है, तो पसंदीदा तरीका यह है कि इसका उपयोग करने के लिए पैरामीटर किया जाए sp_executesql
:
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'SELECT fields FROM table WHERE field23 = @SomeDate_tmp';
EXEC sp_executesql
@SQL,
N'SomeDate_tmp DATETIME',
@SomeDate_tmp = @InputParam;
इस दृष्टिकोण का उपयोग करते हुए, इनपुट पैरामीटर के '2015-10-31'; SELECT * FROM PlainTextCreditCardInfo;
लिए पास होने का प्रयास करने वाले किसी व्यक्ति DATETIME
को संग्रहीत प्रक्रिया को निष्पादित करते समय एक त्रुटि मिलेगी। या यहां तक कि अगर संग्रहीत प्रक्रिया के @InputParameter
रूप में स्वीकार किया जाता है NVARCHAR(100)
, तो DATETIME
उस sp_executesql
कॉल में पास होने के लिए इसे परिवर्तित करना होगा । और भले ही डायनामिक एसक्यूएल में पैरामीटर एक स्ट्रिंग प्रकार है, पहली जगह में संग्रहीत प्रक्रिया में आने से कोई भी एपोस्ट्रोफ स्वचालित रूप से एक डबल एपोस्ट्रोफ से बच जाएगा।
एक कम ज्ञात प्रकार का हमला है जिसमें हमलावर इनपुट फ़ील्ड को एपोस्ट्रोफ के साथ भरने की कोशिश करता है जैसे कि स्टोर्ड प्रोसीजर के अंदर एक स्ट्रिंग जो डायनेमिक एसक्यूएल के निर्माण के लिए उपयोग की जाएगी लेकिन जो बहुत छोटा घोषित किया गया है वह सब कुछ फिट नहीं हो सकता है और अंत में एपोस्ट्रोफ को बाहर धकेलता है और किसी तरह एपोस्ट्रोफ की सही संख्या के साथ समाप्त होता है ताकि स्ट्रिंग के भीतर "बच" न जाए। इसे SQL ट्रंकेशन कहा जाता है और बाला न्यूमेरुला द्वारा "न्यू एसक्यूएल ट्रंकेशन अटैक्स एंड हाउ टु अवे देम" शीर्षक से एक MSDN पत्रिका लेख में बात की गई थी, लेकिन लेख अब ऑनलाइन नहीं है। इस आलेख वाले समस्या - MSDN मैगज़ीन का नवंबर, 2006 संस्करण - केवल Windows मदद फ़ाइल ( inchm) के रूप में उपलब्ध हैप्रारूप)। यदि आप इसे डाउनलोड करते हैं, तो यह डिफ़ॉल्ट सुरक्षा सेटिंग्स के कारण नहीं खुल सकता है। यदि ऐसा होता है, तो MSDNMagazineNession2006en-us.chm फ़ाइल पर राइट-क्लिक करें और "गुण" चुनें। उन टैब में से एक में "इस प्रकार की फ़ाइल पर भरोसा करें" (या ऐसा कुछ) के लिए एक विकल्प होगा, जिसे जांचने / सक्षम करने की आवश्यकता है। "ओके" बटन पर क्लिक करें और फिर .chm फ़ाइल को फिर से खोलने का प्रयास करें।
ट्रंकेशन हमले की एक और विविधता है, एक स्थानीय वैरिएबल का उपयोग "सुरक्षित" उपयोगकर्ता-आपूर्ति मूल्य को संग्रहीत करने के लिए किया जाता है क्योंकि इसमें कोई एकल-उद्धरण दोगुना था ताकि बच जाए, उस स्थानीय चर को भरने और एकल-उद्धरण को रखने के लिए। अतं मै। यहाँ विचार यह है कि यदि स्थानीय चर ठीक से आकार में नहीं है, तो दूसरे एकल-उद्धरण के लिए अंत में पर्याप्त जगह नहीं होगी, एकल एकल-उद्धरण के साथ समाप्त होने वाले चर को छोड़ दें, फिर उस एकल-उद्धरण के साथ संयोजित होता है डायनामिक एसक्यूएल में शाब्दिक मूल्य समाप्त होता है, जो एकल-उद्धरण को एक एम्बेडेड बच गए एकल-उद्धरण में बदल देता है, और फिर डायनामिक एसक्यूएल में स्ट्रिंग शाब्दिक अगले एकल-उद्धरण के साथ समाप्त होता है जिसे अगले स्ट्रिंग शाब्दिक शुरू करने का इरादा था। उदाहरण के लिए:
-- Parameters:
DECLARE @UserID INT = 37,
@NewPassword NVARCHAR(15) = N'Any Value ....''',
@OldPassword NVARCHAR(15) = N';Injected SQL--';
-- Stored Proc:
DECLARE @SQL NVARCHAR(MAX),
@NewPassword_fixed NVARCHAR(15) = REPLACE(@NewPassword, N'''', N''''''),
@OldPassword_fixed NVARCHAR(15) = REPLACE(@OldPassword, N'''', N'''''');
SELECT @NewPassword AS [@NewPassword],
REPLACE(@NewPassword, N'''', N'''''') AS [REPLACE output],
@NewPassword_fixed AS [@NewPassword_fixed];
/*
@NewPassword REPLACE output @NewPassword_fixed
Any Value ....' Any Value ....'' Any Value ....'
*/
SELECT @OldPassword AS [@OldPassword],
REPLACE(@OldPassword, N'''', N'''''') AS [REPLACE output],
@OldPassword_fixed AS [@OldPassword_fixed];
/*
@OldPassword REPLACE output @OldPassword_fixed
;Injected SQL-- ;Injected SQL-- ;Injected SQL--
*/
SET @SQL = N'UPDATE dbo.TableName SET [Password] = N'''
+ @NewPassword_fixed + N''' WHERE [TableNameID] = '
+ CONVERT(NVARCHAR(10), @UserID) + N' AND [Password] = N'''
+ @OldPassword_fixed + N''';';
SELECT @SQL AS [Injected];
अब, निष्पादित होने वाली डायनामिक SQL अब है:
UPDATE dbo.TableName SET [Password] = N'Any Value ....'' WHERE [TableNameID] = 37 AND [Password] = N';Injected SQL--';
वही डायनामिक एसक्यूएल, अधिक पठनीय प्रारूप में है:
UPDATE dbo.TableName SET [Password] = N'Any Value ....'' WHERE [TableNameID] = 37 AND [Password] = N';
Injected SQL--';
इसे ठीक करना आसान है। बस निम्न में से एक करें:
- इसका उपयोग करने के लिए डाइनैमिक SQL UNLESS ABSOLUTELY आवश्यक नहीं है! (मैं इसे पहली बार सूचीबद्ध कर रहा हूं क्योंकि यह वास्तव में विचार करने वाली पहली चीज होनी चाहिए)।
- स्थानीय चर को ठीक से आकार दें (यानी इनपुट पैरामीटर के रूप में दो बार आकार होना चाहिए, बस मामले में सभी वर्ण एकल-उद्धरण हैं।
"निश्चित" मान संग्रहीत करने के लिए एक स्थानीय चर का उपयोग न करें; REPLACE()
सीधे डायनामिक SQL के निर्माण में सीधे डालें :
SET @SQL = N'UPDATE dbo.TableName SET [Password] = N'''
+ REPLACE(@NewPassword, N'''', N'''''') + N''' WHERE [TableNameID] = '
+ CONVERT(NVARCHAR(10), @UserID) + N' AND [Password] = N'''
+ REPLACE(@OldPassword, N'''', N'''''') + N''';';
SELECT @SQL AS [No SQL Injection here];
डायनामिक SQL से अब समझौता नहीं किया जाता है:
UPDATE dbo.TableName SET [Password] = N'Any Value ....''' WHERE [TableNameID] = 37 AND [Password] = N';Injected SQL--';
ऊपर दिए गए ट्रैक्शन उदाहरण के बारे में नोट्स:
- हां, यह एक बहुत ही वंचित उदाहरण है। इंजेक्शन लगाने के लिए केवल 15 अक्षरों में बहुत कुछ नहीं है। ज़रूर, हो सकता है कि
DELETE tableName
विनाशकारी हो, लेकिन बैक-डोर उपयोगकर्ता को जोड़ने या व्यवस्थापक पासवर्ड को बदलने की संभावना कम हो।
- हमले के इस प्रकार शायद कोड के ज्ञान, टेबल नाम, की आवश्यकता आदि कम संभावना यादृच्छिक अजनबी / लिपि-किडी द्वारा किया जाएगा, लेकिन मैं एक जगह है कि एक पूर्व कर्मचारी बल्कि परेशान हैं, जो एक असुरक्षा की जानता था ने हमला किया था पर काम किया है एक विशेष वेब पेज में जिसके बारे में किसी और को पता नहीं था। मतलब, कभी-कभी हमलावरों को सिस्टम का गहन ज्ञान होता है।
- निश्चित रूप से, सभी के पासवर्ड को रीसेट करने की जांच की जा सकती है, जो कंपनी को यह संकेत दे सकता है कि कोई हमला हो रहा है, लेकिन यह अभी भी बैक-डोर उपयोगकर्ता को इंजेक्ट करने के लिए पर्याप्त समय प्रदान कर सकता है या बाद में उपयोग करने / शोषण करने के लिए कुछ माध्यमिक जानकारी प्राप्त कर सकता है।
- भले ही यह परिदृश्य ज्यादातर अकादमिक हो (यानी वास्तविक दुनिया में ऐसा होने की संभावना नहीं है), यह अभी भी असंभव नहीं है।
SQL इंजेक्शन से संबंधित अधिक विस्तृत जानकारी (विभिन्न RDBMS और परिदृश्यों को कवर करते हुए) के लिए, कृपया ओपन वेब एप्लिकेशन सिक्योरिटी प्रोजेक्ट (OWASP) से निम्न देखें :
SQL इंजेक्शन के लिए परीक्षण
एसक्यूएल इंजेक्शन और एसक्यूएल ट्रंकेशन पर संबंधित स्टैक ओवरफ्लो का जवाब:
'एस्केप कैरेक्टर' को बदलने के बाद टी-एसक्यूएल कितना सुरक्षित है?
EXEC usp_actorBirthdays 'Tom', 'Male''; DROP TABLE tblActor'