Чи дійсно параметрів достатньо для запобігання ін’єкціям Sql?


83

Я проповідував як своїм колегам, так і тут на тему SO про користь використання параметрів у запитах SQL, особливо у програмах .NET. Я навіть зайшов так далеко, що пообіцяв їм надати імунітет проти атак SQL-ін'єкцій.

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

Звичайно, є й інші міркування, щоб переконатися, що веб-програма є безпечною (наприклад, дезінфікує введення користувача та інше), але зараз я думаю про ін’єкції SQL. Мене особливо цікавлять атаки на MsSQL 2005 та 2008, оскільки вони є моїми основними базами даних, але всі бази даних цікаві.

Редагувати: Щоб пояснити, що я маю на увазі під параметрами та параметризованими запитами. Використовуючи параметри, я маю на увазі використання "змінних" замість побудови запиту sql у рядку.
Отже, замість цього:

SELECT * FROM Table WHERE Name = 'a name'

Ми робимо це:

SELECT * FROM Table WHERE Name = @Name

а потім встановіть значення параметра @Name на об'єкт запиту / команди.


нам слід уточнити, що мається на увазі під параметрами (як зазначив Джонатан Леффлер) - я думав про параметри збереженої процедури, але є й такі? parms та {0} parms ...
Стівен А. Лоу,

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

Оскільки тегом є asp.net, я припускаю, що ви створюєте веб-програми. У цьому випадку вам також слід подбати про атаки XSS і, можливо, про інші
Spikolynn

Відповіді:


50

Заповнювачів достатньо для запобігання ін’єкцій. Можливо, ви все ще відкриті для переповнення буфера, але це зовсім інший смак атаки від ін’єкції SQL (вектор атаки буде не синтаксисом SQL, а двійковим). Оскільки передані параметри будуть усі захищені належним чином, зловмисник не може передати дані, які будуть оброблятися як "живий" SQL.

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

Однак якщо ви використовуєте параметри як частину конкатенації рядків у вашому динамічному запиті, ви все ще вразливі до введення, оскільки ваші рядки не будуть екрановані, але будуть буквальними. Використання інших типів для параметрів (таких як ціле число) є безпечним.

Тим не менше, якщо ви використовуєте вхідні дані, щоб встановити значення чогось типу security_level, тоді хтось може просто зробити себе адміністраторами у вашій системі та отримати безкоштовний для всіх. Але це лише базова перевірка вхідних даних і не має нічого спільного з введенням SQL.


Ключовим моментом є розуміння проблеми, порушеної відповіддю Стіва Лоу, на яку також вказує стаття @mikekidder, - слід бути обережним, де б не знаходився Динамічний SQL, будь то в додатку чи на сервері. Динамічний SQL небезпечний, але його можна зробити безпечним.
Джонатан Леффлер

"зловмисник не може передавати дані, які будуть оброблятися як" живий "SQL". - Це не зовсім так, див. Приклади нижче.
Booji Boy

Усі наведені нижче приклади визначають "параметризований запит", що означає код SQL, що приймає параметри. Звичайне визначення - це запит, який використовує вашу колекцію параметрів СУБД. За винятком помилки СУБД, ця остання методика запобігає введенню SQL.
HTTP 410,

2
Я прочитав кожне посилання. Будь ласка, цитуйте будь-яке посилання, яке посилається на робочу атаку введення проти збору параметрів СУБД. Дійсно, посилання, яке ви розмістили спеціально, посилається на цей підхід як перемогу введення SQL (див. Розділ "Використання безпечних для типу параметрів SQL").
HTTP 410,

Привіт! Не могли б ви надати посилання на граматику Oracle SQL або щось подібне для підтвердження такої відповіді. Я розумію це і абсолютно з вами згоден, але було б чудово мати офіційне посилання на документацію, граматику тощо BestRegards, Раймбек
Раймбек Рахімбек

13

Ні, як і раніше, коли ви інтерполюєте неперевірені дані до запиту SQL, все ще існує ризик ін’єкції SQL.

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

'SELECT * FROM mytable WHERE colname = ?'

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

'SELECT * FROM ' + @tablename + ' WHERE colname IN (' + @comma_list + ')'
' ORDER BY ' + @colname'

Не має значення, чи використовуєте ви збережені процедури, чи виконуєте динамічні запити SQL безпосередньо з коду програми. Ризик все ще існує.

Засіб правового захисту у цих випадках полягає у застосуванні FIEO за потреби:

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

  • Вихідний вихід: у цьому випадку "вихід" означає розміщення даних у запиті SQL. Ми використовуємо функції для трансформації змінних, які використовуються як строкові літерали у виразі SQL, так що лапки та інші спеціальні символи всередині рядка не використовуються. Ми також повинні використовувати функції для перетворення змінних, які будуть використовуватися як імена таблиць, імен стовпців тощо. Що стосується іншого синтаксису, як динамічне написання цілих виразів SQL, це більш складна проблема.


12

Здається, у цій темі є певна плутанина щодо визначення "параметризованого запиту".

  • SQL, такий як збережений процес, який приймає параметри.
  • SQL, який викликається за допомогою збору параметрів СУБД.

З огляду на попереднє визначення, багато посилань показують діючі атаки.

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

З коментарів я висловлююсь недостатньо чітко, тому ось приклад, який, сподіваюся, буде зрозумілішим:

Цей підхід є відкритим для SQL ін'єкцій

exec dbo.MyStoredProc 'DodgyText'

Цей підхід не відкритий для введення SQL

using (SqlCommand cmd = new SqlCommand("dbo.MyStoredProc", testConnection))
{
    cmd.CommandType = CommandType.StoredProcedure;
    SqlParameter newParam = new SqlParameter(paramName, SqlDbType.Varchar);
    newParam.Value = "DodgyText";
    .....
    cmd.Parameters.Add(newParam);
    .....
    cmd.ExecuteNonQuery();
}

Чи можете ви пояснити, що ви маєте на увазі під колекцією параметрів СУБД на відміну від процедури, яка приймає параметри?
Rune Grimstad,

Rune, прочитайте розділ "Використовувати безпечні для типу параметри SQL" за цим посиланням: msdn.microsoft.com/en-us/library/ms161953.aspx
HTTP 410

Я відповів на оригінальне запитання Rune, перш ніж його було відредаговано разом із оновленням.
mikekidder

Я прочитав і перечитав цю статтю msdn про введення sql, і досі не бачу, як існує різниця між параметрами, які зберігає процедура, і параметрами, які приймає динамічний запит. Крім того, що динамічні запити є динамічними. Вам все одно доведеться прив'язувати параметри, так?
Rune Grimstad,

Різницю робить саме прив’язка. Якщо ви викликаєте збережений proc з параметрами безпосередньо, вхідна фільтрація не проводиться. Але якщо ви прив’яжете (наприклад) за допомогою колекції параметрів SqlCommand у .NET, усі параметри будуть відфільтровані та оброблятись як звичайний текст.
HTTP 410,

10

будь-який параметр sql рядкового типу (varchar, nvarchar тощо), який використовується для побудови динамічного запиту, все ще вразливий

інакше перетворення типу параметра (наприклад, на int, десяткову, дату тощо) повинно усунути будь-яку спробу введення sql через параметр

EDIT: приклад, де параметр @ p1 призначений як ім'я таблиці

create procedure dbo.uspBeAfraidBeVeryAfraid ( @p1 varchar(64) ) 
AS
    SET NOCOUNT ON
    declare @sql varchar(512)
    set @sql = 'select * from ' + @p1
    exec(@sql)
GO

Якщо з випадаючого списку вибрано @ p1, це потенційний вектор атаки sql;

Якщо @ p1 сформульовано програмно без можливості втручання користувача, то це не потенційний вектор атаки sql-ін'єкції


Немає; вся справа в тому, що рядок, переданий СУБД, не є частиною оператора SQL. Тому значення в рядку не має різниці в інтерпретації SQL - лише у значеннях, на які посилається SQL.
Джонатан Леффлер,

Ось як я бачу і параметри. Вони повинні запобігти цій проблемі.
Rune Grimstad

2
Стівен має рацію, якщо, наприклад, ви передаєте рядок до sp, який використовує його для запуску чогось на зразок sp_executeSql (сервер sql), тоді ви все ще ризикуєте ввести sql.
alexmac

@Steven: це не параметр для SQL; вам слід мати заповнювач (знак запитання) замість об’єднання рядків. А SQL не дозволяє вказати назву таблиці за заповнювачем. Це суттєва вразливість SQL-ін'єкції - початкова проблема.
Джонатан Леффлер

@Steven: можливо, термін "параметр" був перевантажений один раз занадто часто. : D
Джонатан Леффлер

6

Переповнення буфера - це не введення SQL.

Параметризовані запити гарантують вам безпеку від введення SQL. Вони не гарантують, що на вашому сервері SQL не буде можливих помилок у вигляді помилок, але ніщо цього не гарантує.


2

Ваші дані не є безпечними, якщо ви використовуєте динамічний sql будь-яким способом у формі або формі, оскільки дозволи повинні бути на рівні таблиці. Так, ви обмежили тип і кількість ін'єкційних атак з цього конкретного запиту, але не обмежили доступ, який користувач може отримати, якщо він або вона знайде шлях до системи, і ви повністю вразливі для внутрішніх користувачів, які отримують доступ до того, чого їм не слід робити з метою вчинити шахрайство або викрасти особисту інформацію для продажу. Динамічний SQL будь-якого типу є небезпечною практикою. Якщо ви використовуєте нединамічні збережені procs, ви можете встановити дозволи на рівні processdure, і жоден користувач не може робити нічого, крім того, що визначено procs (крім звичайних адміністраторів).


отже, урок полягає в тому, що якщо вам потрібно використовувати динамічний sql, робіть це лише всередині збереженої процедури. +1 хороша порада!
Стівен А. Лоу

1
Ні - динамічний SQL в збережених процесорах все ще може вносити недоліки введення SQL, інтерполюючи неперевірені дані в динамічний запит.
Білл Карвін,

Немає уроку в тому, щоб ніколи не використовувати динамічний SQl
HLGEM

@HLGEM - правильно, і автомобілі потрапляють у дорожньо-транспортні пригоди, тому ми ніколи не повинні користуватися автомобілями.
Білл Карвін,

Але динамічний SQL у збереженому proc виконується (за замовчуванням) з дозволу абонента, а не як статичний SQL, який працює з дозволу власника збереженого proc. Це важлива відмінність.
HTTP 410,

1

Зберігається процес може бути вразливим до спеціальних типів ін'єкції SQL через переповнення / усічення, див .: Ін'єкція, увімкнена за допомогою усічення даних тут:

http://msdn.microsoft.com/en-us/library/ms161953.aspx


Якщо ви детально прочитаєте статтю, то побачите, що використання колекції параметрів SQL Server запобігає цій атаці. І це звичайне визначення "параметризованого запиту" - він використовує колекцію параметрів СУБД.
HTTP 410,

1

Тільки пам’ятайте, що за допомогою параметрів ви можете легко зберегти рядок або сказати ім’я користувача, якщо у вас немає жодних політик, "); опустити користувачів таблиці; -"

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


1

Ви можете запустити динамічний sql як приклад

DECLARE @SQL NVARCHAR(4000);
DECLARE @ParameterDefinition NVARCHAR(4000);

SELECT  @ParameterDefinition = '@date varchar(10)'

SET @SQL='Select CAST(@date AS DATETIME) Date'

EXEC sp_executeSQL @SQL,@ParameterDefinition,@date='04/15/2011'
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.