стрілка вверх

Безпека Бази Даних

SQL інєкція

березень 2016

1. ІНТРО

Розглядаю тематику безпечного збереження даних в таблиці БД, що надходять від користувача веб-сайту Навчальна стаття - фільтрація та шифрування вхідних даних. І на офіційному php.net натрапив на невеличку статтю за темою SQL Injection, гадаю буде корисно прочитати тай заодно попрактикуватись із англійським перекладом.



2. SQL Інєкція

Багато хто із веб-розробників не знає, що SQL-запити, що складаються із вхідних даних користувача, можуть бути дещо змінені і як наслідок довіряють власним SQL-запитам до своєї Бази Даних. Це значить, що SQL-запит спроможний обійти перевірку доступу, обійти стандартну процедуру перевірки автентифікації та авторизації та навіть мати змогу доступу до рівня системного адміністратора.

Пряма SQL-Інєкція це техніка, коли зловмисник створює або змінює існуючі SQL-команди, щоб отримати приховані дані чи/або переписати значення даних, або навіть виконати небезпечні команди системного рівня на сервері бази даних. Це досягається за рахунок застосування призначеного для користувача форми введення даних і обєднання його з статичними параметрами для створення SQL-запиту.

Наступні приклади вразливостей з реальних програмних застосунків.

Завдяки обмеженій перевірці вхідних даних та послідуючим зєднанням із базою даних зловмисник може створити обліковий запис із правами адміністратора вашої бази даних.


Приклад 1. Розглянемо приклад розподілу сторінок... та створення прав адміністратора (PostgreSQL).


<?php

$offset 
$argv[0]; // Відсутня перевірка!
$query  "SELECT id, name 
        FROM products 
        ORDER BY name 
        LIMIT 20 
        OFFSET 
$offset;";
$result pg_query($conn$query);

?>

Звичайний користувач активує лінк "попередньої" чи "наступної" сторінки, а змінна $offset кодуватиме значення в URL певної сторінки. Скрипт очікує, що значення $offset повинне бути цифровим. Але, давайте розглянемо, якщо зловмисник змінить код застосувавши функцію urlencode(), де URL має значення:

0; insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd) select 'crack', usesysid, 't','t','crack' from pg_shadow where usename='postgres'; --



Якщо такий випадок станеться, то скрипт надасть права адміністратора. Зауважте, що значення 0; коректне для виконання функції OFFSET і тому запит виконується.


Майте на увазі! Загальна техніка, що змушує парсер SQL-запиту ігнорувати інші запити розробника, це застосувати знак коментарію в SQL:  -- 


Щоб отримати дані паролів необхідно обійти умову вибірки SQL-запиту. Все що для зловмисника необхідно дізнатись, це побачити чи використовуються змінні, що не обробляються належним чином.

Зазвичай фільтри вхідних даних встановлюють перед операторами вибору WHERE, ORDER BY, LIMIT та OFFSET SQL-запиту SELECT.


Якщо ваша база даних підтримує конструкцію UNION атакуючий може спробувати додати додатковий запит, щоб переглянути список паролів з іншої таблиці, тому наполегливо рекомендується застосовувати шифрування паролів.

Приклад 2. Переглядаємо список статей... а також паролі (будь-який сервер БД).

<?php

$query  
"SELECT id, name, inserted, size FROM products
           WHERE size = '
$size'";
$result odbc_exec($conn$query);

?>


Статична частина запиту може бути поєднана із іншим SQL-запитом SELECT, що визначає всі паролі.

' union select '1', concat(uname||'-'||passwd) as name, '1971-01-01', '0' from usertable; --



Якщо даний код буде прописаний в одній із змінних $query, - то, нажаль, можуть статись неприємності для адміністратора БД.


SQL оператор UPDATE також вразливий для атак, так як є можливість створювати інший запит до БД. Зловмисник може перекрутити оператор SET, проте йому попередньо необхідно володіти інформацією про схему запиту. Інформацію про поля паролю та імені користувачів можна отримати чи підібрати досліджуючи/перебираючи змінну імені. Як правило таких імен не так вже й багато.


Приклад 3. Змінюємо пароль... або отримуємо більше переваг (будь-який сервер БД).

<?php
$query 
"UPDATE usertable SET pwd=' $pwd' WHERE uid=' $uid';";
?>

Проте зловмисник може змінити пароль адміністратора відправивши вираз:
  ' or uid like'%admin% до змінної $uid.

або просто, щоб мати більше переваг, встановить значення $pwd на зразок:
hehehe', trusted=100, admin='yes

Запит буде дещо змінено:

<?php

// $uid: ' or uid like '%admin%
$query "UPDATE usertable 
         SET pwd='...' 
         WHERE uid='' or uid like '%admin%';"
;

// $pwd: hehehe', trusted=100, admin='yes
$query  "UPDATE usertable 
         SET pwd='hehehe', trusted=100, admin='yes' 
         WHERE  ...;"
;

?>


Інший приклад того, як можна отримати доступ до операційної системи серверу бази даних.

Приклад 4. Загроза для хосту операційної системи бази даних (MSSQL Server).

<?php

$query  
"SELECT * FROM products WHERE id LIKE '%$prod%'";
$result mssql_query($query);

?>


Якщо зловмисник відправить значення:
a%' exec master..xp_cmdshell 'net user test testpass /ADD' --
до змінної $prod тоді запит $query до серверу БД матиме вигляд:


<?php

$query  
"SELECT * FROM products
           WHERE id LIKE '%a%'
           exec master..xp_cmdshell 'net user test testpass /ADD' --%'"
;
$result mssql_query($query);

?>


MSSQL Server виконає SQL-запит, включаючи додаткову командну стрічку з командою створити аккаунт нового користувача. І якщо ця частина коду виконається, то зловмисник матиме доступ до MSSQLSERVER із свого аккаунту.

Зауважте:
Деякі із прикладів специфічні для окремих БД, і це не значить, що схожі загрози можливі для інших типів БД.

Кожен сервер БД може мати свої специфічні вразливості.



комікс sql інєкція база даних


3. Методика уникнення вразливостей

Очевидно, що зловмисник повинен володіти відмінними знаннями щодо архітектури побудови запитів до серверу бази даних, проте отримати дану інформацію досить легко.

Наприклад, якщо база даних є пакетом з відкритим вихідним кодом або іншим чином загальнодоступних пакетів з встановленням по замовчуванню,- то ця інформація повністю відкрита та доступна.

Ця інформація також може бути отримана, якщо продукт із закритим вихідним кодом або це ваш особистий код,- за умови, якщо провести аналіз повідомлень про помилку, що виводяться на екран користувача.

Інші методи загроз відбуваються через перевірку загальноприйнятих імен таблиць чи атрибутів полів. Наприклад, форма входу, що використовує такі імена як: 'users' таблиця зазвичай має назви колонок 'id', 'username', та 'password'.

Ці загрози для БД можливі за умови, що розробник не переймався питанням безпеки БД. Ніколи не довіряйте любим даним, що надходять із клієнтської сторони, навіть якщо це дані вибору форми select box, приховані вхідні дані полів чи дані cookie.

Перший приклад демонструє, що такий ніби бездоганний запит може наробити лиха.

Приклад 5. Формування запиту безпечної посторінкової навігації.

<?php

settype
($offset'integer');
$query "SELECT id, name 
         FROM products 
         ORDER BY name 
         LIMIT 20 
         OFFSET 
$offset;";

// зауважте, знак %d має тип даних string, застосування ж знаку %s немає сенсу
$query sprintf( "SELECT id, name 
         FROM products 
         ORDER BY name 
         LIMIT 20 
         OFFSET %d;"
,$offset);

?>



Крім того, корисно вести журнал логів запитів до серверу БД. Звісно журнал ніяким чином не унеможливлює вразливість серверу БД, проте він надасть вам інформацію про сторонні запити та корисну інформацію щодо аналізу для покращення безпеки запиту.





Матеріал за ресурсом SQL Injection.
березень 2016