Dlaczego zawsze preferujemy używanie parametrów w poleceniach SQL?

Jestem nowy w pracy z bazami danych. Teraz mogę pisać SELECT, UPDATE, DELETE, i INSERT komendy. Ale widziałem wiele forów, na których wolimy pisać:

SELECT empSalary from employee where salary = @salary

...zamiast:

SELECT empSalary from employee where salary = txtSalary.Text

Dlaczego zawsze wolimy używać parametrów i jak mam ich używać?

Chciałem poznać zastosowanie i korzyści pierwszej metody. Słyszałem nawet o SQL injection, ale nie do końca go Rozumiem. Nawet nie wiem, czy SQL injection jest związane z moim pytaniem.

Author: alamshahbaz16497, 2011-09-21

7 answers

Używanie parametrów pomaga zapobiegać atakom SQL Injection , gdy baza danych jest używana w połączeniu z interfejsem programu, takim jak program komputerowy lub strona internetowa.

W twoim przykładzie użytkownik może bezpośrednio uruchomić kod SQL w Twojej bazie danych, tworząc instrukcje w txtSalary.

Na przykład, gdyby mieli napisać 0 OR 1=1, wykonanym SQL byłby

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

Ponadto Użytkownik może wykonywać znacznie gorsze polecenia przeciwko twojej bazie danych, włącznie z jej usunięciem, jeśli napisali 0; Drop Table employee:

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

Tabela employee zostanie następnie usunięta.


W Twoim przypadku wygląda na to, że używasz .NET. używanie parametrów jest tak proste jak:

C #

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

Edycja 2016-4-25:

Zgodnie z komentarzem George ' a Stockera, zmieniłem przykładowy kod, aby nie używał AddWithValue. Ponadto ogólnie zaleca się zawijanie IDisposable s w using Oświadczenia.

 104
Author: Chad Levy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-02 21:03:27

Masz rację, jest to związane z SQL injection, który jest luką pozwalającą złośliwemu użytkownikowi na wykonywanie dowolnych poleceń z Twoją bazą danych. Ten stary ulubiony komiks xkcd ilustruje koncepcję:

Tutaj wpisz opis obrazka


W twoim przykładzie, jeśli tylko użyjesz:

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

Jesteś otwarty na SQL injection. Na przykład, powiedzmy, że ktoś wchodzi do txtSalary:

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

Gdy wykonasz to zapytanie, wykona ono SELECT i UPDATE albo DROP, czy cokolwiek chcieli. -- na końcu po prostu komentuje resztę twojego zapytania, co byłoby przydatne w ataku, jeśli łączysz cokolwiek po txtSalary.Text.


Poprawnym sposobem jest użycie parametryzowanych zapytań, NP (C#):

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

Dzięki temu możesz bezpiecznie wykonać zapytanie.

Aby dowiedzieć się, jak uniknąć SQL injection w kilku innych językach, sprawdź bobby-tables.com , Strona prowadzona przez więc user .

 62
Author: NullUserException,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:26

W Sql gdy dowolne słowo zawiera znak @ oznacza to, że jest zmienną i używamy tej zmiennej do ustawiania w niej wartości i używania jej na obszarze number na tym samym skrypcie sql, ponieważ jest ona ograniczona tylko na jednym skrypcie, podczas gdy Można zadeklarować wiele zmiennych tego samego typu i nazwy na wielu skryptach. Używamy tej zmiennej w lot procedury składowanej, ponieważ procedury składowane są wstępnie skompilowanymi zapytaniami i możemy przekazać wartości w tej zmiennej ze skryptu, pulpitu i stron internetowych w celu uzyskania dalszych informacji czytaj Declare local Variable, SQL Stored Procedure i SQL Injection.

Przeczytaj również Protect from SQL injection to podpowie jak możesz chronić swoją bazę danych.

Mam nadzieję, że pomoże Ci zrozumieć również wszelkie pytania skomentuj mnie.

 3
Author: Emaad Ali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-21 20:06:27

Inne odpowiedzi wyjaśniają, dlaczego parametry są ważne, ale jest minus! W. Net istnieje kilka metod tworzenia parametrów (Add, AddWithValue), ale wszystkie one wymagają niepotrzebnego martwienia się o nazwę parametru i wszystkie zmniejszają czytelność SQL w kodzie. Kiedy próbujesz medytować nad SQL, musisz polować powyżej lub poniżej, aby zobaczyć, jaka wartość została użyta w parametrze.

Pokornie twierdzę, że moja mała klasa SqlBuilder to najbardziej elegancki sposób zapisu parametryzowanych zapytań . Twój kod będzie wyglądał tak...

C #

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();

Twój kod będzie krótszy i dużo bardziej czytelny. Nie potrzebujesz nawet dodatkowych linii, a gdy czytasz wstecz, nie musisz polować na wartość parametrów. Zajęcia, których potrzebujesz, są tutaj...

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();
}
}
 2
Author: bbsimonbb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-19 09:07:36

Oprócz innych odpowiedzi należy dodać, że parametry nie tylko pomagają zapobiec SQL injection, ale mogą poprawić wydajność zapytań. Buforowanie SQL server sparametryzowało plany zapytań i wykorzystywało je ponownie przy powtarzającym się wykonywaniu zapytań. Jeśli nie sparametryzowałeś swojego zapytania, to SQL server skompilowałby nowy plan dla każdego zapytania (z pewnym wykluczeniem), jeśli tekst zapytania byłby inny.

Więcej informacji o buforowaniu planu zapytań

 2
Author: Oleg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-10 21:35:06

Dwa lata po mojej pierwszej wizycie, recydywuję się...

Dlaczego preferujemy parametry? SQL injection jest oczywiście dużym powodem, ale może być tak, że[5]}potajemnie pragniemy wrócić do SQL jako języka. SQL w literałach ciągów jest już dziwną praktyką kulturową, ale przynajmniej możesz skopiować i wkleić swoje żądanie do management studio. SQL dynamicznie konstruowany z warunkami języka hosta i strukturami kontrolnymi, gdy SQL ma warunki i struktury kontrolne, to tylko barbarzyństwo poziomu 0. Musisz uruchomić aplikację w debugowaniu lub za pomocą śledzenia, aby zobaczyć, co generuje SQL.

Nie zatrzymuj się tylko na parametrach. Idź na całość i użyj QueryFirst (zastrzeżenie: co napisałem). Twój SQL żyje w ... plik sql . Edytujesz go w fantastycznym oknie edytora TSQL, z weryfikacją składni i Intellisense dla tabel i kolumn. Możesz przypisać dane testowe w sekcji specjalne komentarze i kliknąć "Odtwórz", aby uruchomić Twoje zapytanie jest w oknie. Utworzenie parametru jest tak proste, jak umieszczenie "@ myParam " w SQL. Następnie, za każdym razem, gdy zapisujesz, QueryFirst generuje wrapper C# dla Twojego zapytania. Twoje parametry wyskakują, mocno wpisane, jako argumenty metod Execute (). Twoje wyniki są zwracane w ilości lub liście silnie wpisanych POCOs, typów wygenerowanych na podstawie rzeczywistego schematu zwracanego przez twoje zapytanie. Jeśli zapytanie nie zostanie uruchomione, aplikacja nie zostanie skompilowana. Jeśli zmieni się schemat db i zapytanie uruchamia się, ale niektóre kolumny znikają, błąd kompilacji wskazuje na linię w kodzie , która próbuje uzyskać dostęp do brakujących danych. I istnieje wiele innych zalet. Dlaczego chcesz uzyskać dostęp do danych w inny sposób?

 2
Author: bbsimonbb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:26

Stary post, ale chciał upewnić się, że nowicjusze są świadomi procedur przechowywanych .

Moje 10C warto tutaj jest to, że jeśli jesteś w stanie napisać swoje polecenie SQL jako procedura składowana, to moim zdaniem jest optymalne podejście. Ja Zawsze używam przechowywanych procków i nigdy nie pętlę przez rekordy w moim głównym kodzie. Na Przykład: SQL Table > SQL Stored Procedures > IIS/Dot.NET > Class.

Kiedy używasz procedur składowanych, możesz ograniczyć użytkownika do wykonywania tylko uprawnień , co zmniejsza bezpieczeństwo ryzyko .

Twoja procedura składowana jest z natury sparameryzowana i możesz określić parametry wejściowe i wyjściowe.

Procedura składowana (jeśli zwraca dane za pomocą Instrukcji SELECT) może być dostępna i odczytywana dokładnie w taki sam sposób, jak zwykła Instrukcja SELECT w Twoim kodzie.

Działa również szybciej, ponieważ jest kompilowany na serwerze SQL.

Czy wspomniałem też, że można wykonać kilka kroków, np. update tabelę, sprawdzić wartości na innym serwerze DB, a potem raz w końcu koniec, powrót danych do klienta, wszystko na tym samym serwerze, bez interakcji z klientem. Jest to więc znacznie szybsze niż kodowanie tej logiki w kodzie.

 0
Author: Arvin Amir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-27 06:31:42