4.3 KiB
title | localeTitle |
---|---|
Query Parameterization | Параметрирование запроса |
Параметрирование запроса
Обычная ошибка при подключении вашей программы к базе данных - это принять вход пользователя и применить его непосредственно к базе данных, не проверив его в первую очередь. Это опасная привычка, и вы можете услышать, что более опытные разработчики предупреждают других о том, что они «дезинфицируют ввод» или «параметризовать запросы».
Начнем с краткого примера, демонстрирующего проблему:
(следующие фрагменты написаны на C # для MySQL, но концепция применима к любому языку и базе данных)
Проблема
public void RetrieveEmployeeInfo(string username)
{
using (var connection = new MySqlConnection("valid_connection_string"))
{
var query = "SELECT * FROM EMPLOYEES WHERE USERNAME = '" + username + "'";
using (var command = new MySqlCommand(query, connection))
{
var reader = command.ExecuteReader();
while (reader.Read())
{
// do something with the results of your query, like display the employee
}
}
}
}
На первый взгляд это может показаться довольно безобидным. Если пользователь вводит «JDOE» в вашу программу и передается этой функции, вы в конечном итоге выполняете такой запрос:
SELECT * FROM EMPLOYEES WHERE USERNAME = 'JDOE';
Проблема становится более очевидной, если вы считаете, что происходит, если пользователь не вводит то, что вы ожидаете. Что делать, если они набирают что-то вроде JDOE'; DROP TABLE EMPLOYEES; --
? Теперь ваша строка запроса будет выглядеть так, что выберет информацию о сотруднике, а затем удалит всю таблицу РАБОТНИКОВ!
SELECT * FROM EMPLOYEES WHERE USERNAME = 'JDOE'; DROP TABLE EMPLOYEES; --'
Решение
Чтобы предотвратить такие проблемы, мы можем параметризовать наши запросы. Давайте посмотрим на другой пример:
public void RetrieveEmployeeInfo(string username)
{
using (var connection = new MySqlConnection("valid_connection_string"))
{
var query = "SELECT * FROM EMPLOYEES WHERE USERNAME = @username";
using (var command = new MySqlCommand(query, connection))
{
command.Parameters.AddWithValue("username", username);
var reader = command.ExecuteReader();
while (reader.Read())
{
// do something with the results of your query, like display the employee
}
}
}
}
Теперь, что произойдет, если пользователь вводит в JDOE'; DROP TABLE EMPLOYEES; --
? Наша программа заканчивает выполнение запроса, подобного этому, и, не найдя сотрудника, чье имя пользователя действительно соответствует этому вводу, просто не возвращает записей.
SELECT * FROM EMPLOYEES WHERE USERNAME = 'JDOE\'; DROP TABLE EMPLOYEES; --'
Независимо от того, какой язык или база данных вы используете, если вы рассматриваете запрос базы данных с использованием пользовательского ввода, проверьте документацию для правильного способа параметризации запросов.