Я знаю, що PreparedStatements уникають / запобігають ін'єкції SQL. Як це робити? Чи буде запит остаточної форми, побудований за допомогою PreparedStatements, рядок чи іншим чином?
Я знаю, що PreparedStatements уникають / запобігають ін'єкції SQL. Як це робити? Чи буде запит остаточної форми, побудований за допомогою PreparedStatements, рядок чи іншим чином?
Відповіді:
Проблема введення SQL полягає в тому, що вхід користувача використовується як частина оператора SQL. Використовуючи підготовлені оператори, ви можете змусити користувачів вводити дані як вміст параметра (а не як частина команди SQL).
Але якщо ви не використовуєте вхід користувача як параметр для підготовленого оператора, а натомість будуєте команду SQL, з'єднуючи рядки разом, ви все ще вразливі до ін'єкцій SQL навіть при використанні підготовлених операторів.
Розглянемо два способи зробити те саме:
PreparedStatement stmt = conn.createStatement("INSERT INTO students VALUES('" + user + "')");
stmt.execute();
Або
PreparedStatement stmt = conn.prepareStatement("INSERT INTO student VALUES(?)");
stmt.setString(1, user);
stmt.execute();
Якщо "користувач" прийшов із введення користувача, а введення користувача було
Robert'); DROP TABLE students; --
Тоді, в першу чергу, вам покладуть шланг. По-друге, ви б були в безпеці, і столики маленького Бобі будуть зареєстровані для вашої школи.
Щоб зрозуміти, як PreparedStatement перешкоджає ін'єкції SQL, нам потрібно зрозуміти фази виконання SQL Query.
1. Фаза компіляції. 2. Фаза виконання.
Щоразу, коли двигун SQL-сервера отримує запит, він повинен пройти нижче фаз,
Етап розбору та нормалізації: На цій фазі запит перевіряється на синтаксис та семантику. Він перевіряє, чи існує таблиця посилань та стовпці, використані в запиті, чи ні. У нього також є багато інших завдань, які потрібно виконати, але не будемо детально розбиратися.
Фаза компіляції: На цій фазі ключові слова, які використовуються в запиті, такі як select, from, where etc., перетворюються у формат, зрозумілий машиною. Це етап, коли інтерпретується запит і вирішується відповідна дія, яку слід здійснити. У нього також є багато інших завдань, які потрібно виконати, але не будемо детально розбиратися.
План оптимізації запитів: На цьому етапі створюється Дерево рішень для пошуку шляхів виконання запиту. Він визначає кількість способів виконання запиту та вартість, пов'язану з кожним способом виконання запиту. Він вибирає найкращий план для виконання запиту.
Кеш: Найкращий план, вибраний у Плані оптимізації запитів, зберігається в кеші, так що кожного разу, коли наступний раз надходить той самий запит, йому не доведеться повторно проходити через Фазу 1, Фазу 2 та Фазу 3. Коли наступний раз надходить запит, він перевірятиметься безпосередньо в кеші та вибирається звідти для виконання.
Фаза виконання:
На цій фазі поданий запит виконується і дані повертаються користувачеві як ResultSet
об'єкт.
PreparedStatements не є повними запитами SQL і містять заповнювачі, які під час виконання замінюються фактичними даними, наданими користувачем.
Кожен раз, коли будь-який готовий заставник, що містить заповнювачі, передається в двигун SQL Server, він проходить нижче фаз
ОНОВЛЕННЯ користувача встановити ім'я користувача =? а пароль =? ДЕ id =?
Наведений вище запит буде проаналізований, скомпільований із заповнювачами як спеціальна обробка, оптимізований та кешований. Запит на цьому етапі вже складений та перетворений у машинозрозумілому форматі. Таким чином, ми можемо сказати, що Запит, що зберігається в кеші, має попередній збір, і лише заповнювачі потрібно замінити на дані, надані користувачем.
Тепер під час запуску, коли надходять дані, що надаються користувачем, попередньо складений запит вибирається з кешу, а заповнювачі замінюються наданими користувачем даними.
(Пам'ятайте, що після того, як власники місць замінюються на дані користувачів, остаточний запит не збирається / інтерпретується знову, і двигун SQL Server розглядає дані користувачів як чисті дані, а не SQL, який потрібно розбирати або компілювати знову; в цьому полягає краса PreparedStatement. )
Якщо запит не повинен повторно проходити фазу компіляції, будь-які дані, замінені на заповнювачах, трактуються як чисті дані і не мають значення для двигуна SQL Server, і він безпосередньо виконує запит.
Примітка: саме фаза компіляції після фази розбору розуміє / інтерпретує структуру запитів та надає їй значущу поведінку. У разі PreparedStatement запит складається лише один раз, а кешований зібраний запит підбирається весь час для заміни даних користувача та виконання.
Завдяки функції разової компіляції PreparedStatement вона не містить атаки SQL Injection.
Ви можете отримати детальне пояснення з прикладом тут: https://javabypatel.blogspot.com/2015/09/how-prepared-statement-in-java-prevents-sql-injection.html
SQL, використовуваний у PreparedStatement, попередньо компілюється на драйвер. З цього моменту параметри надсилаються драйверу як буквальні значення, а не виконувані частини SQL; таким чином, жоден SQL не може бути введений за допомогою параметра. Ще одним корисним побічним ефектом PreparedStatements (прекомпіляція + надсилання лише параметрів) є покращена продуктивність при запуску оператора кілька разів навіть з різними значеннями параметрів (якщо припускати, що драйвер підтримує PreparedStatements), оскільки драйвер не повинен виконувати розбір SQL і компіляцію кожного час зміни параметрів.
Я думаю, це буде рядок. Але вхідні параметри будуть надіслані до бази даних, а відповідні кадри / перетворення будуть застосовані до створення фактичного оператора SQL.
Щоб навести приклад, він може спробувати перевірити, чи працює CAST / конверсія.
Якщо він працює, він може створити з нього остаточну заяву.
SELECT * From MyTable WHERE param = CAST('10; DROP TABLE Other' AS varchar(30))
Спробуйте приклад з оператором SQL, що приймає числовий параметр.
Тепер спробуйте передати рядкову змінну (з числовим вмістом, прийнятним як числовий параметр). Чи викликає це помилка?
Тепер спробуйте передати рядкову змінну (із вмістом, неприйнятним як числовий параметр). Бачите, що відбувається?
Підготовлена заява є більш безпечною. Він перетворить параметр у вказаний тип.
Наприклад stmt.setString(1, user);
, перетворить user
параметр у рядок.
Припустимо, що параметр містить рядок SQL, що містить виконувану команду : використання підготовленого оператора цього не дозволить.
До цього додається метахарактор (він же автоматичне перетворення).
Це робить його більш безпечним.
Введення SQL: коли користувач має шанс ввести щось, що може бути частиною оператора sql
Наприклад:
Рядок запит = "ВСТАВИТЬ У НАВЧАЛЬНІ ЗНАЧЕННЯ (" "+ користувач +" ")
при введенні користувачем "Роберт"); ДРОПУВАТИ ТАБЛИЦІ студентів; - ”як вхід, він спричиняє введення SQL
Наскільки підготовлена заява перешкоджає цьому?
Рядок запит = "ВСТАВИТЬ У ВІДЧУКУ студентів (" "+": ім'я "+" ")"
parametri.addValue ("ім'я", користувач);
=> коли користувач знову вводить "Роберт"); ДРОПУВАТИ ТАБЛИЦІ студентів; - ", рядок введення попередньо компілюється на драйвер у вигляді буквальних значень, і я думаю, що це може бути зроблено як:
CAST ('Роберт'); ДРОПУВАТИ ТАБЛИЦІ студентів; - 'AS варчар (30))
Тож наприкінці рядок буде буквально вставлено як назва до таблиці.
http://blog.linguiming.com/index.php/2018/01/10/why-prepared-statement-avoids-sql-injection/
CAST(‘Robert’);
з CAST(‘Robert’); DROP TABLE students; –‘ AS varchar(30))
ламається, то вона б продовжувала скидати стіл, якби це було так. Це зупиняє ін'єкцію, тому я вважаю, що приклад просто недостатній для пояснення сценарію.
Підготовлений стан:
1) Попередня компіляція та кешування на стороні БД оператора SQL призводить до загального швидшого виконання та можливості повторного використання одного і того ж оператора SQL у партіях.
2) Автоматична профілактика атак ін'єкцій SQL шляхом вбудованого виходу цитат та інших спеціальних символів. Зверніть увагу, що для цього потрібно використовувати будь-який із методів набору PreparedStatementXxx ().
Як пояснено в цій публікації , PreparedStatement
одне не допоможе вам, якщо ви все ще об'єднуєте струни.
Наприклад, один зловмисник може все ще зробити наступне:
Не тільки SQL, але навіть JPQL або HQL можуть бути порушені, якщо ви не використовуєте параметри прив'язки.
Підсумок, ви ніколи не повинні використовувати конкатенацію рядків при побудові операторів SQL. Для цього використовуйте спеціальний API:
У Підготовлені Звіти користувач змушений вводити дані як параметри. Якщо користувач вводить деякі вразливі висловлювання, такі як DROP TABLE або SELECT * FROM USERS, на дані не впливатиме, оскільки вони вважатимуться параметрами оператора SQL