77 lines
4.3 KiB
Markdown
77 lines
4.3 KiB
Markdown
|
---
|
|||
|
title: Query Parameterization
|
|||
|
localeTitle: Параметрирование запроса
|
|||
|
---
|
|||
|
## Параметрирование запроса
|
|||
|
|
|||
|
Обычная ошибка при подключении вашей программы к базе данных - это принять вход пользователя и применить его непосредственно к базе данных, не проверив его в первую очередь. Это опасная привычка, и вы можете услышать, что более опытные разработчики предупреждают других о том, что они «дезинфицируют ввод» или «параметризовать запросы».
|
|||
|
|
|||
|
Начнем с краткого примера, демонстрирующего проблему:
|
|||
|
|
|||
|
_(следующие фрагменты написаны на C # для MySQL, но концепция применима к любому языку и базе данных)_
|
|||
|
|
|||
|
### Проблема
|
|||
|
|
|||
|
```csharp
|
|||
|
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» в вашу программу и передается этой функции, вы в конечном итоге выполняете такой запрос:
|
|||
|
|
|||
|
```sql
|
|||
|
SELECT * FROM EMPLOYEES WHERE USERNAME = 'JDOE';
|
|||
|
```
|
|||
|
|
|||
|
Проблема становится более очевидной, если вы считаете, что происходит, если пользователь _не_ вводит то, что вы ожидаете. Что делать, если они набирают что-то вроде `JDOE'; DROP TABLE EMPLOYEES; --` ? Теперь ваша строка запроса будет выглядеть так, что выберет информацию о сотруднике, а затем удалит всю таблицу РАБОТНИКОВ!
|
|||
|
|
|||
|
```sql
|
|||
|
SELECT * FROM EMPLOYEES WHERE USERNAME = 'JDOE'; DROP TABLE EMPLOYEES; --'
|
|||
|
```
|
|||
|
|
|||
|
### Решение
|
|||
|
|
|||
|
Чтобы предотвратить такие проблемы, мы можем параметризовать наши запросы. Давайте посмотрим на другой пример:
|
|||
|
|
|||
|
```csharp
|
|||
|
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; --` ? Наша программа заканчивает выполнение запроса, подобного этому, и, не найдя сотрудника, чье имя пользователя действительно соответствует этому вводу, просто не возвращает записей.
|
|||
|
|
|||
|
```sql
|
|||
|
SELECT * FROM EMPLOYEES WHERE USERNAME = 'JDOE\'; DROP TABLE EMPLOYEES; --'
|
|||
|
```
|
|||
|
|
|||
|
Независимо от того, какой язык или база данных вы используете, если вы рассматриваете запрос базы данных с использованием пользовательского ввода, проверьте документацию для правильного способа параметризации запросов.
|