SQL इंजेक्शन एक संग्रहीत कार्यविधि के अंदर इस क्वेरी पर क्यों नहीं होता है?


18

मैंने निम्नलिखित संग्रहित प्रक्रिया की:

ALTER PROCEDURE usp_actorBirthdays (@nameString nvarchar(100), @actorgender nvarchar(100))
AS
SELECT ActorDOB, ActorName FROM tblActor
WHERE ActorName LIKE '%' + @nameString + '%'
AND ActorGender = @actorgender

अब, मैंने ऐसा कुछ करने की कोशिश की। शायद मैं यह गलत कर रहा हूं, लेकिन मैं यह सुनिश्चित करना चाहता हूं कि इस तरह की प्रक्रिया किसी भी SQL इंजेक्शन को रोक सकती है:

EXEC usp_actorBirthdays 'Tom', 'Male; DROP TABLE tblActor'

नीचे दी गई छवि एसएसएम को एसएसएम में निष्पादित किए जाने से ऊपर बताती है और परिणाम एक त्रुटि के बजाय सही ढंग से प्रदर्शित हो रहे हैं:

यहां छवि विवरण दर्ज करें

Btw, मैंने उस हिस्से को अर्धविराम के बाद जोड़ा, जब क्वेरी निष्पादित की गई थी। फिर मैंने इसे फिर से निष्पादित किया, लेकिन जब मैंने यह देखने के लिए जांच की कि टेबल tblActor मौजूद है या नहीं, यह अभी भी था। क्या मुझसे कुछ ग़लत हो रहा है? या यह वास्तव में इंजेक्शन-प्रूफ है? मुझे लगता है कि जो मैं यहां पूछने की कोशिश कर रहा हूं वह यह है कि क्या यह सुरक्षित जैसी संग्रहीत प्रक्रिया है? धन्यवाद।


क्या आपने यह कोशिश की हैEXEC usp_actorBirthdays 'Tom', 'Male''; DROP TABLE tblActor'
MarmiK

जवाबों:


38

यह कोड ठीक से काम करता है क्योंकि यह है:

  1. परिमाणित, और
  2. कोई डायनेमिक एसक्यूएल नहीं कर रहा

काम करने के लिए 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--';

इसे ठीक करना आसान है। बस निम्न में से एक करें:

  1. इसका उपयोग करने के लिए डाइनैमिक SQL UNLESS ABSOLUTELY आवश्यक नहीं है! (मैं इसे पहली बार सूचीबद्ध कर रहा हूं क्योंकि यह वास्तव में विचार करने वाली पहली चीज होनी चाहिए)।
  2. स्थानीय चर को ठीक से आकार दें (यानी इनपुट पैरामीटर के रूप में दो बार आकार होना चाहिए, बस मामले में सभी वर्ण एकल-उद्धरण हैं।
  3. "निश्चित" मान संग्रहीत करने के लिए एक स्थानीय चर का उपयोग न करें; 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--';

ऊपर दिए गए ट्रैक्शन उदाहरण के बारे में नोट्स:

  1. हां, यह एक बहुत ही वंचित उदाहरण है। इंजेक्शन लगाने के लिए केवल 15 अक्षरों में बहुत कुछ नहीं है। ज़रूर, हो सकता है कि DELETE tableNameविनाशकारी हो, लेकिन बैक-डोर उपयोगकर्ता को जोड़ने या व्यवस्थापक पासवर्ड को बदलने की संभावना कम हो।
  2. हमले के इस प्रकार शायद कोड के ज्ञान, टेबल नाम, की आवश्यकता आदि कम संभावना यादृच्छिक अजनबी / लिपि-किडी द्वारा किया जाएगा, लेकिन मैं एक जगह है कि एक पूर्व कर्मचारी बल्कि परेशान हैं, जो एक असुरक्षा की जानता था ने हमला किया था पर काम किया है एक विशेष वेब पेज में जिसके बारे में किसी और को पता नहीं था। मतलब, कभी-कभी हमलावरों को सिस्टम का गहन ज्ञान होता है।
  3. निश्चित रूप से, सभी के पासवर्ड को रीसेट करने की जांच की जा सकती है, जो कंपनी को यह संकेत दे सकता है कि कोई हमला हो रहा है, लेकिन यह अभी भी बैक-डोर उपयोगकर्ता को इंजेक्ट करने के लिए पर्याप्त समय प्रदान कर सकता है या बाद में उपयोग करने / शोषण करने के लिए कुछ माध्यमिक जानकारी प्राप्त कर सकता है।
  4. भले ही यह परिदृश्य ज्यादातर अकादमिक हो (यानी वास्तविक दुनिया में ऐसा होने की संभावना नहीं है), यह अभी भी असंभव नहीं है।

SQL इंजेक्शन से संबंधित अधिक विस्तृत जानकारी (विभिन्न RDBMS और परिदृश्यों को कवर करते हुए) के लिए, कृपया ओपन वेब एप्लिकेशन सिक्योरिटी प्रोजेक्ट (OWASP) से निम्न देखें :
SQL इंजेक्शन के लिए परीक्षण

एसक्यूएल इंजेक्शन और एसक्यूएल ट्रंकेशन पर संबंधित स्टैक ओवरफ्लो का जवाब:
'एस्केप कैरेक्टर' को बदलने के बाद टी-एसक्यूएल कितना सुरक्षित है?


2
ओह, बहुत बहुत धन्यवाद, यह एक महान जवाब है। मैं अब समझता हूँ। मैं वास्तव में आपके द्वारा अंत में बताई गई तकनीक को देखना चाहूंगा जहां हमलावर एपोस्ट्रोफ के साथ इनपुट क्षेत्र को भरने की कोशिश करता है, अगर आप इसे पा सकते हैं। अग्रिम में धन्यवाद। मैं इसे खुला रखने जा रहा हूं, यदि आप इसे नहीं पाते हैं, तो मैं इसे उत्तर के रूप में चुनूंगा।
रवि

1
@ रवि मुझे लिंक मिला लेकिन यह अब लेख के लिए नहीं मिलता है क्योंकि वे सभी अब संग्रहीत हैं। लेकिन मैंने कुछ जानकारी और उपयोगी लिंक जोड़े और मैं अभी भी उन अभिलेखों के भीतर लेख खोजने की कोशिश कर रहा हूं।
सोलोमन रटज़की

1
धन्यवाद srutzsky, मैं OWASP लेख और इंजेक्शन के लिए परीक्षण पढ़ूंगा। अगर मुझे सही से याद है, सुरक्षा परीक्षण के लिए कमजोर वेब ऐप 'म्यूटिलिडे', में एसक्यूएल इंजेक्शन है, जिसे मैंने कॉलेज में 'OR 1 = 1' स्ट्रिंग के साथ प्रदर्शित किया था, जिसके परिणामस्वरूप मुझे mutillidae में वेब ऐप में लॉग इन करना पड़ा, जैसे कि मैं सोच। जब मुझे पहली बार SQL इंजेक्शन लगाया गया था।
रवि

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

2

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

मैंने इस बारे में ब्लॉग किया: http://blogs.lobsterpot.com.au/2015/02/10/sql-injection-the-golden-rule/


धन्यवाद, रोब, मेरे पास दिन में बाद में पढ़ने के लिए एक बुकमार्क है।
रवि
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.