हम हमेशा SQL स्टेटमेंट में मापदंडों का उपयोग करना क्यों पसंद करते हैं?


114

मैं डेटाबेस के साथ काम करने के लिए बहुत नया हूं। अब मैं लिख सकते हैं SELECT, UPDATE, DELETE, और INSERTआदेशों। लेकिन मैंने कई मंचों को देखा है जहाँ हम लिखना पसंद करते हैं:

SELECT empSalary from employee where salary = @salary

...के बजाय:

SELECT empSalary from employee where salary = txtSalary.Text

हम हमेशा मापदंडों का उपयोग करना क्यों पसंद करते हैं और मैं उनका उपयोग कैसे करूंगा?

मैं पहली विधि के उपयोग और लाभों को जानना चाहता था। मैंने एसक्यूएल इंजेक्शन के बारे में भी सुना है, लेकिन मैं इसे पूरी तरह से नहीं समझता। मुझे यह भी नहीं पता कि एसक्यूएल इंजेक्शन मेरे प्रश्न से संबंधित है या नहीं।


2
आप सही हैं, यह SQL इंजेक्शन से संबंधित है। मापदंडों से कैसे निपटें आमतौर पर आपके प्रोग्राम में जो भी भाषा / रूपरेखा चल रही है उसकी जिम्मेदारी है, और भाषा निर्भर हो सकती है। कृपया अपने RDBMS (मददगार), और ORM फ्रैमवर्क (आवश्यक) दोनों पोस्ट करें।
क्लॉकवर्क-म्यूजियम

1
मैं C # प्रोग्रामिंग भाषा और Sql Server 2008 को डेटाबेस के रूप में उपयोग कर रहा हूं। मैं माइक्रोसॉफ्ट डॉटनेट फ्रेमवर्क 4.0 का उपयोग कर रहा हूं। मुझे वास्तव में खेद है, कि मुझे यकीन नहीं है कि आप क्या पूछ रहे हैं (आरडीबीएमएस या ओआरएम), शायद आप मुझे अपना आरडीबीएमएस और ओआरएम फ्रेमवर्क संस्करण अभी दे सकते हैं :-)। बहुत बहुत धन्यवाद
सैंडी

1
RDBMS आपका डेटाबेस है, आपके मामले में SQL Server 2008। आपका ORM वह तरीका है जिसके द्वारा आप अपने डेटाबेस तक पहुंच रहे हैं, इस स्थिति में, ADO.NET। अन्य में LINQ to SQL और Entity फ्रेमवर्क शामिल हैं । वास्तव में, एक बार जब आप ADO.NET और SQL की मूल बातें सीख लेते हैं, तो मैं आपको ORM या EF जैसे ORM का उपयोग करने की सलाह देता हूं क्योंकि वे कई मुद्दों का ध्यान रखते हैं जिनका आप मैन्युअल रूप से SQL लिखकर सामना करेंगे।
चाड लेवी

जवाबों:


129

मापदंडों का उपयोग SQL इंजेक्शन के हमलों को रोकने में मदद करता है जब डेटाबेस को प्रोग्राम इंटरफ़ेस जैसे डेस्कटॉप प्रोग्राम या वेब साइट के साथ संयोजन में उपयोग किया जाता है।

आपके उदाहरण में, एक उपयोगकर्ता सीधे बयानों को क्राफ्ट करके अपने डेटाबेस पर SQL कोड चला सकता है txtSalary

उदाहरण के लिए, यदि वे लिखना चाहते थे 0 OR 1=1, तो निष्पादित SQL होगा

 SELECT empSalary from employee where salary = 0 or 1=1

जिससे सभी साम्राज्य वापस हो जाएंगे।

इसके अलावा, कोई उपयोगकर्ता आपके डेटाबेस के खिलाफ इससे भी बदतर कमांड का प्रदर्शन कर सकता है, जिसमें इसे हटाना भी अगर वे लिखा है 0; Drop Table employee:

SELECT empSalary from employee where salary = 0; Drop Table employee

तब तालिका employeeहटा दी जाएगी।


आपके मामले में, ऐसा लगता है कि आप .NET का उपयोग कर रहे हैं। मापदंडों का उपयोग करना उतना ही आसान है:

सी#

string sql = "SELECT empSalary from employee where salary = @salary";

using (SqlConnection connection = new SqlConnection(/* connection info */))
using (SqlCommand command = new SqlCommand(sql, connection))
{
    var salaryParam = new SqlParameter("salary", SqlDbType.Money);
    salaryParam.Value = txtMoney.Text;

    command.Parameters.Add(salaryParam);
    var results = command.ExecuteReader();
}

VB.NET

Dim sql As String = "SELECT empSalary from employee where salary = @salary"
Using connection As New SqlConnection("connectionString")
    Using command As New SqlCommand(sql, connection)
        Dim salaryParam = New SqlParameter("salary", SqlDbType.Money)
        salaryParam.Value = txtMoney.Text

        command.Parameters.Add(salaryParam)

        Dim results = command.ExecuteReader()
    End Using
End Using

2016-4-25 संपादित करें:

जॉर्ज स्टॉकर की टिप्पणी के अनुसार, मैंने उपयोग नहीं करने के लिए नमूना कोड बदल दिया AddWithValue। इसके अलावा, यह आमतौर पर अनुशंसा की जाती है कि आप बयानों IDisposableमें लपेटते हैं using


महान समाधान। लेकिन क्या आप थोड़ा और समझा सकते हैं, क्यों और कैसे मापदंडों का उपयोग करना सुरक्षित है। मेरा मतलब है कि यह अभी भी लग रहा है कि sql कमांड समान होगी
सैंडी

क्या हम sql कमांड में कई पैरामीटर जोड़ सकते हैं। जैसे हमें INSERT कमांड में आवश्यकता हो सकती है?
सैंडी

2
SQL सर्वर मापदंडों के अंदर पाठ को केवल इनपुट के रूप में मानता है और इसे कभी भी निष्पादित नहीं करेगा।
चाड लेवी

3
हां, आप कई पैरामीटर जोड़ सकते हैं Insert Into table (Col1, Col2) Values (@Col1, @Col2):। अपने कोड में आप कई AddWithValueएस जोड़ेंगे ।
चाड लेवी

1
कृपया AddWithValue का उपयोग न करें! यह अंतर्निहित रूपांतरण मुद्दों का कारण बन सकता है। हमेशा आकार स्पष्ट रूप से सेट करें और पैरामीटर मान जोड़ें parameter.Value = someValue
जॉर्ज स्टॉकर

75

आप सही हैं, यह एसक्यूएल इंजेक्शन से संबंधित है , जो एक भेद्यता है जो एक malicioius उपयोगकर्ता को अपने डेटाबेस के खिलाफ मनमाने ढंग से बयानों को निष्पादित करने की अनुमति देता है। यह पुराना समय पसंदीदा XKCD कॉमिक अवधारणा को दर्शाता है:

उनकी बेटी का नाम हेल्प आई एम है जो एक ड्राइवर लाइसेंस फैक्ट्री में फंसा हुआ है।


अपने उदाहरण में, यदि आप अभी उपयोग करते हैं:

var query = "SELECT empSalary from employee where salary = " + txtSalary.Text;
// and proceed to execute this query

आप SQL इंजेक्शन के लिए खुले हैं। उदाहरण के लिए, कहें कि कोई व्यक्ति txtSalary में प्रवेश करता है:

1; UPDATE employee SET salary = 9999999 WHERE empID = 10; --
1; DROP TABLE employee; --
// etc.

जब आप इस क्वेरी को निष्पादित करते हैं, तो यह SELECTएक UPDATEया एक DROP, या जो भी वे चाहते थे, प्रदर्शन करेंगे । --अंत में बस आपकी शेष क्वेरी, जो हमले में उपयोगी हो सकता है अगर आप के बाद कुछ भी श्रृंखलाबद्ध थे बाहर टिप्पणी txtSalary.Text


सही तरीका है कि मानकीकृत प्रश्नों का उपयोग करें, जैसे (C #):

SqlCommand query =  new SqlCommand("SELECT empSalary FROM employee 
                                    WHERE salary = @sal;");
query.Parameters.AddWithValue("@sal", txtSalary.Text);

इसके साथ, आप क्वेरी को सुरक्षित रूप से निष्पादित कर सकते हैं।

कई अन्य भाषाओं में एसक्यूएल इंजेक्शन से कैसे बचा जाए, इस संदर्भ के लिए, bobby-tables.com , एक एसओ उपयोगकर्ता द्वारा रखी गई वेबसाइट की जांच करें


1
महान समाधान। लेकिन क्या आप थोड़ा और समझा सकते हैं, क्यों और कैसे मापदंडों का उपयोग करना सुरक्षित है। मेरा मतलब है कि यह अभी भी लग रहा है कि sql कमांड समान होगी।
सैंडी

1
@ user815600: एक आम ग़लतफ़हमी - आप अभी भी मानते हैं कि मापदंडों के साथ क्वेरी मूल्य में ले जाएगी और वास्तविक मूल्यों के लिए मापदंडों को स्थानापन्न करेगी - सही? नहीं यह नहीं हो रहा है! - इसके बजाय, मापदंडों के साथ SQL स्टेटमेंट SQL सर्वर को प्रेषित किया जाएगा, मापदंडों और उनके मूल्यों की एक सूची के साथ - SQL स्टेटमेंट समान नहीं होने वाला है
marc_s

1
इसका मतलब है कि sql इंजेक्शन की निगरानी sql सर्वर आंतरिक तंत्र या सुरक्षा द्वारा की जा रही है। धन्यवाद।
सैंडी

4
बहुत से मुझे कार्टून पसंद हैं, यदि आप टेबल छोड़ने के लिए पर्याप्त विशेषाधिकार के साथ अपना कोड चला रहे हैं, तो संभवतः आपके पास व्यापक मुद्दे हैं।
दार्शनिक

9

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

क्वेरी प्लान कैशिंग के बारे में अधिक जानकारी


1
यह एक से अधिक विचारशील हो सकता है। यहां तक ​​कि "छोटी" क्वेरी को हजारों या लाखों बार निष्पादित किया जा सकता है, प्रभावी रूप से पूरे क्वेरी कैश को फ्लश कर सकता है।
जेम्स

5

मेरे जाने के दो साल बाद , मैं याद कर रहा हूँ ...

हम मापदंडों को क्यों पसंद करते हैं? SQL इंजेक्शन जाहिर तौर पर एक बड़ा कारण है, लेकिन क्या ऐसा हो सकता है कि हम गुप्त रूप से SQL को भाषा के रूप में वापस पाने के लिए तरस रहे हों । स्ट्रिंग लीटर में एसक्यूएल पहले से ही एक अजीब सांस्कृतिक अभ्यास है, लेकिन कम से कम आप प्रबंधन स्टूडियो में अपने अनुरोध को कॉपी और पेस्ट कर सकते हैं। SQL गतिशील रूप से होस्ट भाषा सशर्त और नियंत्रण संरचनाओं के साथ निर्मित होता है, जब SQL में सशर्त और नियंत्रण संरचनाएं होती हैं, यह केवल स्तर 0 बर्बरता है। आपको अपना ऐप डीबग में या ट्रेस के साथ चलाना होगा, यह देखने के लिए कि यह किस SQL ​​को उत्पन्न करता है।

सिर्फ मापदंडों के साथ मत रोको। पूरे रास्ते जाओ और QueryFirst (अस्वीकरण: जो मैंने लिखा था) का उपयोग करें। आपकी SQL एक .sql फ़ाइल में रहती है। आप इसे अपने तालिकाओं और स्तंभों के लिए वाक्यविन्यास सत्यापन और Intellisense के साथ शानदार TSQL संपादक विंडो में संपादित करते हैं। आप विशेष टिप्पणी अनुभाग में डेटा परीक्षण कर सकते हैं और विंडो में अपनी क्वेरी को वहीं चलाने के लिए "प्ले" पर क्लिक कर सकते हैं। एक पैरामीटर बनाना आपके SQL में "@myParam" डालने जितना आसान है। फिर, हर बार जब आप बचत करते हैं, तो QueryFirst आपकी क्वेरी के लिए C # रैपर बनाता है। Execute () विधियों के तर्क के रूप में आपके पैरामीटर पॉप अप, दृढ़ता से टाइप किए जाते हैं। आपके परिणाम एक IEnumerable या दृढ़ता से टाइप किए गए POCOs की सूची में वापस आ जाते हैं, वास्तविक स्कीमा से उत्पन्न प्रकार आपकी क्वेरी में वापस आ जाते हैं। यदि आपकी क्वेरी नहीं चलती है, तो आपका ऐप संकलित नहीं होगा। यदि आपका db स्कीमा बदलता है और आपकी क्वेरी चलती है, लेकिन कुछ कॉलम गायब हो जाते हैं, तो संकलन त्रुटि आपके कोड में मौजूद लाइन को इंगित करती हैजो लापता डेटा तक पहुँचने की कोशिश करता है। और कई अन्य फायदे हैं। आप डेटा को किसी अन्य तरीके से एक्सेस क्यों करना चाहेंगे?


4

Sql में जब किसी भी शब्द में @ चिन्ह होता है तो इसका मतलब है कि यह परिवर्तनशील है और हम इस चर का उपयोग इसमें मूल्य निर्धारित करने के लिए करते हैं और इसे उसी sql स्क्रिप्ट पर संख्या क्षेत्र पर उपयोग करते हैं क्योंकि यह केवल एकल स्क्रिप्ट पर प्रतिबंधित है, जबकि आप बहुत से चर घोषित कर सकते हैं एक ही प्रकार और कई स्क्रिप्ट पर नाम। हम इस चर को संग्रहीत कार्यविधि में बहुत उपयोग करते हैं क्योंकि संग्रहीत कार्यविधि पूर्व-संकलित प्रश्न हैं और हम इन चर में मानों को स्क्रिप्ट, डेस्कटॉप और वेबसाइटों से आगे की जानकारी पढ़ने के लिए दे सकते हैं , स्थानीय परिवर्तनशील , Sql संग्रहित प्रक्रिया और sql इंजेक्शन पढ़ सकते हैं ।

इसके अलावा पढ़ एसक्यूएल इंजेक्शन से बचाने के लिए यह कैसे आप अपने डेटाबेस की रक्षा कर सकते मार्गदर्शन करेंगे।

आशा है कि यह आपको किसी भी प्रश्न को समझने में मेरी मदद करेगा।


3

अन्य उत्तर कवर करते हैं कि पैरामीटर महत्वपूर्ण क्यों हैं, लेकिन एक नकारात्मक पहलू है! .Net में, पैरामीटर बनाने के लिए कई तरीके हैं (Add, AddWithValue), लेकिन वे सभी आपको चिंता करने की आवश्यकता है, अनावश्यक रूप से, पैरामीटर नाम के बारे में, और वे सभी कोड में SQL की पठनीयता को कम करते हैं। जब आप SQL पर ध्यान लगाने की कोशिश कर रहे होते हैं, तो आपको पैरामीटर के ऊपर या नीचे शिकार करने की आवश्यकता होती है, यह देखने के लिए कि पैरामीटर में किस मूल्य का उपयोग किया गया है।

मैं विनम्रतापूर्वक दावा करता हूं कि मेरा छोटा SqlBuilder वर्ग पैरामीटर प्रश्नों को लिखने का सबसे सुंदर तरीका है । आपका कोड इस तरह दिखेगा ...

सी#

var bldr = new SqlBuilder( myCommand );
bldr.Append("SELECT * FROM CUSTOMERS WHERE ID = ").Value(myId);
//or
bldr.Append("SELECT * FROM CUSTOMERS WHERE NAME LIKE ").FuzzyValue(myName);
myCommand.CommandText = bldr.ToString();

आपका कोड छोटा और बहुत अधिक पठनीय होगा। आपको अतिरिक्त लाइनों की भी आवश्यकता नहीं है, और, जब आप वापस पढ़ रहे हैं, तो आपको मापदंडों के मूल्य के लिए शिकार करने की आवश्यकता नहीं है। आपको जिस वर्ग की आवश्यकता है वह यहाँ है ...

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;

public class SqlBuilder
{
private StringBuilder _rq;
private SqlCommand _cmd;
private int _seq;
public SqlBuilder(SqlCommand cmd)
{
    _rq = new StringBuilder();
    _cmd = cmd;
    _seq = 0;
}
public SqlBuilder Append(String str)
{
    _rq.Append(str);
    return this;
}
public SqlBuilder Value(Object value)
{
    string paramName = "@SqlBuilderParam" + _seq++;
    _rq.Append(paramName);
    _cmd.Parameters.AddWithValue(paramName, value);
    return this;
}
public SqlBuilder FuzzyValue(Object value)
{
    string paramName = "@SqlBuilderParam" + _seq++;
    _rq.Append("'%' + " + paramName + " + '%'");
    _cmd.Parameters.AddWithValue(paramName, value);
    return this;
}
public override string ToString()
{
    return _rq.ToString();
}
}

आपके पैरामीटर का नामकरण निश्चित रूप से मदद करता है जब सर्वर चल रहे प्रश्नों को प्रोफाइल करता है।
डेव आर

मेरे बॉस ने भी यही बात कही। यदि सार्थक पैरामीटर नाम आपके लिए महत्वपूर्ण हैं, तो मान विधि में एक सर्वोपरि तर्क जोड़ें। मुझे संदेह है कि आप अनावश्यक रूप से चीजों को जटिल कर रहे हैं।
bbsimonbb

बुरा विचार। जैसा कि पहले कहा गया था, AddWithValueअंतर्निहित रूपांतरण मुद्दों का कारण बन सकता है।
एडम कैल्वेट बोहल

@ एडम आप सही कह रहे हैं, लेकिन यह AddWithValue () को बहुत व्यापक रूप से इस्तेमाल होने से नहीं रोकता है, और मुझे नहीं लगता कि यह विचार को अमान्य करता है। लेकिन इस बीच, मैं पैरामीटर प्रश्नों को लिखने का एक बेहतर तरीका लेकर आया हूं , और वह AddWithValue () :-)
bbsimonbb

सही! वादा है कि मैं जल्द ही देखने जा रहा हूँ!
एडम कैल्वेट बोहल

3

पुरानी पोस्ट, लेकिन यह सुनिश्चित करना चाहती थी कि नए लोग स्टोर्ड प्रक्रियाओं से अवगत हों ।

यहां मेरा 10 write मूल्य यह है कि यदि आप अपने SQL स्टेटमेंट को एक संग्रहीत कार्यविधि के रूप में लिखने में सक्षम हैं , तो मेरे विचार में वह इष्टतम तरीका है। मैं हमेशा अपने मुख्य कोड में रिकॉर्ड के माध्यम से संग्रहीत procs और लूप का उपयोग नहीं करता। उदाहरण के लिए SQL Table > SQL Stored Procedures > IIS/Dot.NET > Class:।

आप संग्रहित प्रक्रियाओं का उपयोग करते हैं, तो आप करने के लिए उपयोगकर्ता को प्रतिबंधित कर सकते निष्पादित केवल अनुमति है, इस प्रकार सुरक्षा जोखिम को कम करने

आपकी संग्रहीत प्रक्रिया स्वाभाविक रूप से पैरामिज़र है, और आप इनपुट और आउटपुट पैरामीटर निर्दिष्ट कर सकते हैं।

संग्रहीत कार्यविधि (यदि यह SELECTविवरण के माध्यम से डेटा लौटाता है ) तक पहुँचा जा सकता है और ठीक उसी तरह से पढ़ा जा सकता है जैसे आप नियमित करते हैंSELECT अपने कोड में विवरण देते हैं।

यह SQL सर्वर पर संकलित होने के साथ ही तेजी से चलता है।

क्या मैंने यह भी उल्लेख किया है कि आप कई चरणों को कर सकते हैं, उदाहरण के लिए updateएक तालिका, दूसरे DB सर्वर पर मानों की जांच करें, और फिर एक बार अंत में समाप्त होने पर, क्लाइंट को सभी डेटा, एक ही सर्वर पर और क्लाइंट के साथ कोई इंटरैक्शन न करें। तो यह आपके कोड में इस तर्क को कूटने से ज्यादा तेज है।

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