Почему мы всегда предпочитаем использовать параметры в SQL-запросах?

Я очень новичок в работе с базами данных. Теперь я могу писать!--2-->, UPDATE, DELETE и INSERT команды. Но я видел много форумов, где мы предпочитаем написать:

SELECT empSalary from employee where salary = @salary

...вместо:

SELECT empSalary from employee where salary = txtSalary.Text

почему мы всегда предпочитаем использовать параметры, и как бы мне их использовать?

Я хотел узнать об использовании и преимуществах первого метода. Я даже слышал о SQL-инъекции, но я не совсем понимаю это. Я даже не знаю, является ли SQL-инъекция связано с моим вопросом.

7 ответов


использование параметров помогает предотвратить SQL-инъекции когда база данных используется в сочетании с программой интерфейс настольного приложения или веб-сайта.

в вашем примере пользователь может напрямую запускать SQL-код в вашей базе данных, создавая операторы в txtSalary.

например, если бы они написали 0 OR 1=1, выполняемый SQL будет

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

в котором все empSalaries были бы возвращенный.

кроме того, пользователь может выполнять гораздо худшие команды против вашей базы данных, включая ее удаление, если они написали 0; Drop Table employee:

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

в таблице employee затем будет удален.


в вашем случае, похоже, что вы используете .Сеть. Использование параметров так же просто, как:

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

изменить 2016-4-25:

As в комментарии Джорджа Стокера я изменил пример кода, чтобы не использовать AddWithValue. Кроме того, обычно рекомендуется, чтобы вы обернули IDisposables в using заявления.


вы правы, это связано с SQL-инъекций, что является уязвимостью, которая позволяет пользователю malicioius выполнять произвольные операторы против вашей базы данных. Это любимое старое время комикс XKCD иллюстрирует концепцию:

enter image description here


в вашем примере, если вы просто использовать:

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, или что они хотели. The -- в конце просто комментирует остальную часть вашего запроса, что было бы полезно в атаке, если бы вы объединяли что-либо после txtSalary.Text.


правильный способ-использовать параметризованные запросы, например (на C#):

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

С этим вы можете безопасно выполнить запрос.

для справки о том, как избежать SQL-инъекции в нескольких других языки, проверить bobby-tables.com сайт поддерживается так что пользователь.


в Sql, когда любое слово содержит @ sign, это означает, что оно является переменным, и мы используем эту переменную, чтобы установить значение в нем и использовать его в числовой области на том же сценарии sql, потому что он ограничен только на одном скрипте, в то время как вы можете объявить много переменных одного типа и имени на многих скриптах. Мы используем эту переменную в партии хранимых процедур, потому что хранимые процедуры являются предварительно скомпилированными запросами, и мы можем передавать значения в этой переменной из сценария, рабочего стола и веб-сайтов для получения дополнительной информации Объявить Локальную Переменную, Хранимая Процедура Sql и среда SQL инъекций.

Читайте также защита от SQL-инъекций это поможет вам защитить вашу базу данных.

надеюсь, что это поможет вам понять также любой вопрос комментарий ко мне.


другие ответы обложка почему параметры важны, но есть и обратная сторона! В .net существует несколько методов создания параметров (Add, AddWithValue), но все они требуют, чтобы вы без необходимости беспокоились об имени параметра, и все они уменьшают читаемость SQL в коде. Прямо когда вы пытаетесь медитировать на SQL, вам нужно охотиться выше или ниже, чтобы увидеть, какое значение было использовано в параметре.

Я смиренно утверждаю, что мой маленький класс SqlBuilder самый элегантный способ написания параметризованных запросов. Ваш код будет выглядеть так...

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

ваш код будет короче и более читабельным. Вам даже не нужны дополнительные строки, и, когда вы читаете назад, вам не нужно искать значение параметров. Класс вам нужно здесь...

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

в дополнение к другим ответам нужно добавить, что параметры не только помогают предотвратить SQL-инъекцию, но и может повысить производительность запросов. Кэширование SQL server параметризованных планов запросов и их повторное использование при выполнении повторяющихся запросов. Если вы не параметризовали свой запрос, то sql server будет компилировать новый план для каждого запроса(С некоторым исключением) выполнение, если текст запроса будет отличаться.

дополнительные сведения о плане запроса кэширование


два года после первый, Я рецидивов...

Почему мы предпочитаем параметров? SQL-инъекция, очевидно, является большой причиной, но может быть, что мы тайно стремимся вернуться к SQL язык. SQL в строковых литералах уже является странной культурной практикой, но, по крайней мере, вы можете скопировать и вставить свой запрос в management studio. SQL динамически строится с условными обозначениями языка хоста и структурами управления, когда SQL имеет условные и контрольные структуры, это просто Уровень 0 варварства. Вы должны запустить приложение в debug или с трассировкой, чтобы увидеть, какой SQL он генерирует.

Не останавливайтесь только на параметрах. Пройдите весь путь и используйте QueryFirst (отказ от ответственности: который я написал). Ваш SQL живет в a .sql-файл. Вы редактируете его в окне редактора fabulous TSQL с проверкой синтаксиса и Intellisense для ваших таблиц и столбцов. Вы можете назначить тестовые данные в специальный раздел комментариев и нажмите кнопку "play", чтобы запустить запрос прямо там, в окне. Создать параметр так же просто, как поместить "@myParam" в SQL. Затем при каждом сохранении QueryFirst создает оболочку C# для вашего запроса. Ваши параметры всплывают, строго типизированные, как аргументы методов Execute (). Ваши результаты возвращаются в IEnumerable или список строго типизированных POCOs, типов, созданных из фактической схемы, возвращенной вашим запросом. Если запрос не выполняется, приложение не будет компилировать. Если схема БД изменяется и запрос выполняется, но некоторые столбцы исчезают, ошибка компиляции указывает на строка в коде который пытается получить доступ к отсутствующим данным. И есть множество других преимуществ. зачем вы хотите получить доступ к данным любым другим способом?


старый пост, но хотел убедиться, что новички знают о хранимых процедур.

мой 10C стоит вот что, если вы можете написать свой SQL-оператор как хранимая процедура, что, на мой взгляд, является оптимальным подходом. Я!--5-->всегда используйте сохраненные процессы и никогда не просматривайте записи в моем основном коде. Например:SQL Table > SQL Stored Procedures > IIS/Dot.NET > Class.

когда вы используете хранимые процедуры, вы можете ограничить пользователя выполнить разрешения только, так снижение рисков безопасности.

хранимая процедура по своей сути парамеризуется, и вы можете указать входные и выходные параметры.

хранимая процедура (если она возвращает данные через SELECT оператор) можно получить доступ и прочитать точно так же, как вы бы обычный SELECT оператор в вашем коде.

Он также работает быстрее, поскольку он скомпилирован на SQL Server.

Я также упоминал, что вы можете сделать несколько шагов, например update таблица, проверьте значения на другом сервере БД, а затем, когда, наконец, закончите, верните данные клиенту, все на том же сервере, и никакого взаимодействия с клиентом. Таким образом, это намного быстрее, чем кодирование этой логики в вашем коде.