SQL -инъекция
SQL-инъекция
Внедрение SQL — это метод внедрения кода, который может разрушить вашу базу данных.
SQL-инъекция — один из самых распространенных методов веб-хакерства.
Внедрение SQL — это размещение вредоносного кода в операторах SQL посредством ввода с веб-страницы.
SQL на веб-страницах
Внедрение SQL обычно происходит, когда вы запрашиваете у пользователя ввод, например, его имя пользователя/идентификатор пользователя, и вместо имени/идентификатора пользователь дает вам инструкцию SQL, которую вы неосознанно запускаете в своей базе данных.
Посмотрите на следующий пример, в котором оператор создается
SELECT
путем добавления переменной (txtUserId) в строку выбора. Переменная извлекается из пользовательского ввода (getRequestString):
Пример
txtUserId = getRequestString("UserId");
txtSQL = "SELECT *
FROM Users WHERE UserId = " + txtUserId;
В оставшейся части этой главы описываются потенциальные опасности использования пользовательского ввода в операторах SQL.
Внедрение SQL на основе 1 = 1 всегда верно
Посмотрите еще раз на пример выше. Первоначальной целью кода было создание инструкции SQL для выбора пользователя с заданным идентификатором пользователя.
Если ничто не мешает пользователю ввести «неправильный» ввод, пользователь может ввести какой-нибудь «умный» ввод, например:
Идентификатор пользователя:
Тогда оператор SQL будет выглядеть так:
SELECT * FROM Users WHERE UserId = 105 OR 1=1;
Приведенный выше SQL действителен и вернет ВСЕ строки из таблицы «Пользователи», поскольку ИЛИ 1=1 всегда ИСТИНА.
Пример выше выглядит опасным? Что делать, если таблица «Пользователи» содержит имена и пароли?
Приведенный выше оператор SQL во многом похож на этот:
SELECT UserId, Name, Password
FROM Users WHERE UserId = 105 or 1=1;
Хакер может получить доступ ко всем именам пользователей и паролям в базе данных, просто вставив 105 ИЛИ 1=1 в поле ввода.
Внедрение SQL на основе ""="" всегда верно
Вот пример входа пользователя на веб-сайт:
Имя пользователя:
Пароль:
Пример
uName = getRequestString("username");
uPass = getRequestString("userpassword");
sql = 'SELECT * FROM Users WHERE Name ="' + uName + '" AND Pass ="' + uPass +
'"'
Результат
SELECT * FROM Users WHERE Name ="John Doe" AND Pass ="myPass"
Хакер может получить доступ к именам пользователей и паролям в базе данных, просто вставив "ИЛИ ""=" в текстовое поле имени пользователя или пароля:
Имя пользователя:
Пароль:
Код на сервере создаст допустимый оператор SQL, подобный этому:
Результат
SELECT * FROM Users WHERE Name ="" or ""="" AND Pass ="" or ""=""
Вышеупомянутый SQL действителен и вернет все строки из таблицы «Пользователи», поскольку ИЛИ «» =» всегда ИСТИНА.
SQL-инъекция на основе пакетных операторов SQL
Большинство баз данных поддерживают пакетный оператор SQL.
Пакет операторов SQL — это группа из двух или более операторов SQL, разделенных точкой с запятой.
Приведенный ниже оператор SQL вернет все строки из таблицы «Пользователи», а затем удалит таблицу «Поставщики».
Пример
SELECT * FROM Users; DROP TABLE Suppliers
Посмотрите на следующий пример:
Пример
txtUserId = getRequestString("UserId");
txtSQL = "SELECT *
FROM Users WHERE UserId = " + txtUserId;
И следующий ввод:
Идентификатор пользователя:
Правильный оператор SQL будет выглядеть следующим образом:
Результат
SELECT * FROM Users WHERE
UserId = 105; DROP TABLE Suppliers;
Используйте параметры SQL для защиты
Чтобы защитить веб-сайт от SQL-инъекций, вы можете использовать параметры SQL.
Параметры SQL — это значения, которые добавляются к запросу SQL во время выполнения контролируемым образом.
Пример Razor ASP.NET
txtUserId = getRequestString("UserId");
txtSQL = "SELECT *
FROM Users WHERE UserId = @0";
db.Execute(txtSQL,txtUserId);
Обратите внимание, что параметры представлены в операторе SQL с помощью маркера @.
Механизм SQL проверяет каждый параметр, чтобы убедиться, что он корректен для своего столбца и обрабатывается буквально, а не как часть выполняемого SQL.
Другой пример
txtNam = getRequestString("CustomerName");
txtAdd = getRequestString("Address");
txtCit = getRequestString("City");
txtSQL = "INSERT INTO Customers (CustomerName,Address,City) Values(@0,@1,@2)";
db.Execute(txtSQL,txtNam,txtAdd,txtCit);
Примеры
В следующих примерах показано, как создавать параметризованные запросы на некоторых распространенных веб-языках.
ВЫБЕРИТЕ ЗАЯВЛЕНИЕ В ASP.NET:
txtUserId = getRequestString("UserId");
sql = "SELECT * FROM Customers WHERE CustomerId = @0";
command = new SqlCommand(sql);
command.Parameters.AddWithValue("@0",txtUserId);
command.ExecuteReader();
ВСТАВЬТЕ В ЗАЯВЛЕНИЕ В ASP.NET:
txtNam = getRequestString("CustomerName");
txtAdd = getRequestString("Address");
txtCit = getRequestString("City");
txtSQL = "INSERT INTO Customers (CustomerName,Address,City) Values(@0,@1,@2)";
command = new SqlCommand(txtSQL);
command.Parameters.AddWithValue("@0",txtNam);
command.Parameters.AddWithValue("@1",txtAdd);
command.Parameters.AddWithValue("@2",txtCit);
command.ExecuteNonQuery();
ВСТАВИТЬ В ЗАЯВЛЕНИЕ В PHP:
$stmt = $dbh->prepare("INSERT INTO Customers (CustomerName,Address,City)
VALUES (:nam, :add, :cit)");
$stmt->bindParam(':nam', $txtNam);
$stmt->bindParam(':add', $txtAdd);
$stmt->bindParam(':cit', $txtCit);
$stmt->execute();