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 завжди True
Подивіться на приклад вище ще раз. Початковою метою коду було створити оператор SQL для вибору користувача з заданим ідентифікатором (id) користувача.
Якщо ніщо не заважає користувачеві ввести "неправильний" input, користувач може ввести якийсь "розумний" input, як це:
UserId:
Тоді SQL інструкція виглядатиме так:
SELECT * FROM Users WHERE UserId = 105 OR 1=1;
Наведений вище SQL дійсний і поверне ВСІ рядки з таблиці "Users", оскільки OR 1=1 завжди TRUE.
Чи виглядає наведений вище приклад небезпечним? Що робити, якщо таблиця "Users" містить імена та паролі?
Наведена вище SQL інструкція майже така сама:
SELECT UserId, Name, Password FROM Users WHERE UserId = 105 or 1=1;
Хакер може отримати доступ до всіх імен користувачів і паролів у базі даних, просто вставивши 105 АБО 1=1 у поле введення.
SQL Ін’єкція на основі ""="" завжди True
Ось приклад входу користувача на веб-сайт:
Username:
Password:
Приклад
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"
Хакер може отримати доступ до імен користувачів і паролів у базі даних, просто вставивши " OR ""=" у текстове поле імені користувача (User Name) чи пароля (Password):
User Name:
Password:
Код на сервері створить таку валідну (дійсну) SQL інструкцію:
Результат
SELECT * FROM Users WHERE Name ="" or ""="" AND Pass ="" or ""=""
Наведений вище SQL валідний і повертатиме всі рядки з таблиці "Users", оскільки OR ""="" завжди має значення TRUE.
SQL Ін’єкція на основі пакетних SQL інструкцій
Більшість баз даних підтримують групову SQL інструкцію.
Пакет інструкцій SQL – це група з двох або більше інструкцій SQL, розділених крапкою з комою.
Наведена нижче SQL інструкція поверне всі рядки з таблиці "Users" ("Користувачі"), а потім видалить таблицю "Suppliers" ("Постачальники").
Приклад
SELECT * FROM Users; DROP TABLE Suppliers
Подивіться на наступний приклад:
Приклад
txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;
І наступний input (введення):
User id:
Валідна SQL інструкція виглядатиме так:
Результат
SELECT * FROM Users WHERE UserId = 105; DROP TABLE Suppliers;
Використовуйте параметри SQL для захисту
Щоб захистити вебсайт від впровадження SQL, ви можете використовувати параметри SQL.
Параметри SQL – це значення, які контрольованим чином додаються до запиту SQL під час виконання.
ASP.NET Razor Приклад
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);
Приклади
У наведених нижче прикладах показано, як створювати параметризовані запити деякими поширеними веб-мовами.
SELECT інструкція в ASP.NET:
txtUserId = getRequestString("UserId");
sql = "SELECT * FROM Customers WHERE CustomerId = @0";
command = new SqlCommand(sql);
command.Parameters.AddWithValue("@0",txtUserId);
command.ExecuteReader();
INSERT INTO інструкція в 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();
INSERT INTO інструкція в 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();