Перейти к основному содержанию
`Ctrl`+`K`

# SQL-инъекции

SQL-инъекция (sqli) — это уязвимость безопасности, которая позволяет злоумышленнику вмешиваться в запросы к базе данных приложения, внедряя злонамеренный SQL-код через входные данные, меняя исходный SQL-запрос.
Проблема возникает, когда приложение «слепо» объединяет пользовательские данные с кодом SQL-запроса, не проверяя и не обрабатывая их.

## Пример инъекции

Исходный запрос:

    SELECT * FROM users WHERE username = '[user_input_1]' AND password = '[user_input_2]'

Злоумышленник вводит в поле `username` специальную строку: `OR 1=1 --`. Поле `password` он может оставить пустым или заполнить чем угодно.

Злонамеренный ввод:

    user_input_1: **admin' or 1=1 --**
    user_input_2: **[любой]**

Результат:

    SELECT * FROM users WHERE username = 'admin' or 1=1 --' AND password = 'text'

## Чем опасны SQL-инъекции?

Злоумышленник может:

1. Обойти аутентификацию.

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

3. Изменять и удалять данные: удалять, изменять, добавлять записи.

4. Выполнять команды на сервере БД: в некоторых случаях атака может привести к полному захвату сервера.

## Методы защиты

1. Подготовленные выражения (Prepared Statement) - наиболее эффективный метод защиты. Это механизм выполнения SQL-запросов, при котором шаблон SQL-запроса и данные передаются отдельно. Это полностью исключает возможность SQL-инъекций. Предпочтительнее использовать именно этот метод защиты.

    val svName = "admin"
    val svPass = "qwerty1234"
    SQL(s"SELECT * FROM users WHERE username = {sUserName} AND password = {sPassHash}")
        .on("sUserName" -> svName, "sPassHash" -> svPass)

2. Использование функций экранирования. Если использовать подготовленные выражения не представляется возможным, необходимо воспользоваться функциями экранирования, они «обезвреживают» специальные символы:

- `escapeString(input: String, quoteValue: Boolean): String` - для экранирования строки. Экранирует символы одинарной кавычки (“) в строке. Если `quoteValue = true`, заключит значение в одинарные кавычки.

        val sUserInput = SqlEscape.escapeString("' union select id from Btk_User --", false)
        SQL(s"SELECT id FROM Bs_Goods WHERE sName = '$sUserInput' ")

- `escapeNumber(input: String): String` - для экранирования числа. Удаляет спецсимволы („;“, „–“, „/“, „/“, пробелы).

        val sIdGood = SqlEscape.escapeNumber("1 OR 1=1 --")
        SQL(s"""SELECT id FROM Bs_Goods WHERE id = $sIdGood""")

- `escapeName(input: String): String` - для экранирования имен сущностей, например имена таблиц и колонок. Экранирует одинарные кавычки („), удаляет спецсимволы `';', '--', '/*', '*/', '(', ')'`.

- `escapeDate(input: String): String` - для экранирования даты. Экранирует символы одинарной кавычки („).

- `escapeJson(input: String): String` - для экранирования json. Экранирует символы одинарной кавычки („).

- `escapeBoolean(input: String): String` - для экранирования булевого значения. Если строка не равна «true», вернет «false».