Чи можу я захиститись від інжекцій SQL, уникаючи одноцитатних та оточуючих введення користувачем за допомогою одних лапок?


139

Я усвідомлюю, що параметризовані SQL-запити є оптимальним способом оздоровити введення користувачів під час створення запитів, що містять введення користувача, але мені цікаво, що не так у прийнятті вводу користувача та уникненні будь-яких єдиних лапок та оточення цілої рядки одинарними лапками. Ось код:

sSanitizedInput = "'" & Replace(sInput, "'", "''") & "'"

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

Ми використовуємо Microsoft SQL Server 2000, для якого я вважаю, що одна цитата - це єдиний роздільник рядків і єдиний спосіб уникнути розділового рядка, тому немає можливості виконати що-небудь, у що вводиться користувач.

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

Що не так з цим кодом? Чи є спосіб отримати атаку ін'єкцій SQL повз цю техніку санітарії? Приклад користувача, який використовує цю методику, був би дуже корисним.


ОНОВЛЕННЯ:

Я досі не знаю жодного способу ефективного запуску атаки ін'єкцій SQL проти цього коду. Кілька людей припустили, що зворотна косою рискою вдасться уникнути однієї цитати, а інша залишить кінець рядка, щоб решта рядка була виконана як частина команди SQL, і я розумію, що цей метод буде працювати для введення SQL у база даних MySQL, але в SQL Server 2000 єдиний спосіб (який мені вдалося знайти) вийти з однієї цитати - це ще одна одноцитата; нахили в косому напрямку це не робитимуть.

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

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


17
@BryanH Признання не розуміти, як загальноприйнята мудрість стосується конкретного випадку, і просити приклад про такий конкретний випадок - це не прихильність, це покірність. Роздратовано, коли хтось запитує приклад того, чому загальноприйнята мудрість є правильною, з іншого боку, може здатися нахабною. Обґрунтування конкретних прикладів часто є прекрасним способом дослідження та навчання. Те, як ОП пішло з цим сумнівом, було дуже корисним для мого розуміння теми, особливо коли він пояснив знайдену відповідь.
SantiBailors

@patrik Щойно натрапив на це, коли я працюю над тим самим фрагментом коду, але намагаюся вийти з рядка та ввести запит. Ви коли-небудь це розуміли?
3therk1ll

1
@ 3therk1ll найкраще не намагатися, вам краще використовувати параметризований SQL: blog.codinghorror.com/…
Патрік

@Patrick, я підходжу до цього з точки зору нападників!
3therk1ll

Відповіді:


87

Перш за все, це лише погана практика. Перевірка введення завжди необхідна, але вона також завжди непроста.
Що ще гірше, перевірка чорного списку завжди проблематична, набагато краще чітко і чітко визначити, які значення / формати ви приймаєте. Справді, це не завжди можливо, але певною мірою це потрібно робити завжди.
Деякі наукові роботи на цю тему:

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

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

Правильний спосіб зробити це:

  • Перевірка білого списку: тип, довжина, формат або прийняті значення
  • Якщо ви хочете до чорного списку, йдіть прямо вперед. Уникнення цитат - це добре, але в контексті інших пом'якшень.
  • Використовуйте об'єкти Command і Parameter для попереднього аналізу та перевірки
  • Викликати лише параметризовані запити.
  • А ще краще використовувати виключно збережені процедури.
  • Уникайте використання динамічного SQL і не використовуйте рядкове з'єднання для створення запитів.
  • Якщо ви використовуєте SP, ви також можете обмежити дозволи в базі даних виконувати лише необхідні SP-адреси, а не отримувати доступ до таблиць безпосередньо.
  • Ви також можете легко переконатися, що вся база коду має доступ до БД тільки через SP ...

2
При правильному використанні динамічне об'єднання SQL та рядків можна безпечно використовувати з параметризованими запитами (тобто з sp_executesqlзамість них EXEC). Тобто, ви можете динамічно генерувати свій SQL-оператор до тих пір, поки жоден зв'язаний текст не надходить від користувача. Це також має переваги від продуктивності; sp_executesqlпідтримує кешування
Брайан

2
@Brian, ну так :). Але насправді, як часто ви бачите програмістів, що роблять це? Більше того, типовий сценарій, коли "потрібен" динамічний SQL, вимагає введення користувачем як частини запиту (нібито). Якби ви могли зробити sp_executesql, вам (як правило) в першу чергу не знадобиться динамічний sql.
AviD

Я нарешті зіткнувся з ситуацією, яка дала мені зрозуміти, що можна використовувати unicode, щоб проникнути повз заміни рядка. Введений текст був набраний у Word, який змінив апостроф із прямолінійної версії на "фігурний" апостроф (який більше нагадує кому), на який не впливала заміна рядка, але SQL розглядали як роздільник рядків Сервер. Дякуємо за відповідь AviD (і всі інші)!
Патрік

1
@ElRonnoco впевнений, але я не знижую це, оскільки я бачив це в дикій природі більше разів, ніж ви могли б подумати ...
AviD

1
@AviD Я оновив посилання на PDF-файл з контрабандою SQL, який ви написали до єдиної версії, яку я міг знайти в Інтернеті ... Будь ласка, повідомте нам, чи є інше місце для вашої роботи.
Майкл Фредріксон

41

Гаразд, ця відповідь стосуватиметься оновлення питання:

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

Тепер, окрім зворотного косого нахилу MySQL - і враховуючи, що ми говоримо насправді про MSSQL, існує фактично 3 можливих способи все-таки SQL вводити ваш код

sSanitizedInput = "'" & Замінити (sInput, "'", "'" ") &"' "

Враховуйте, що всі вони не будуть дійсними в усі часи і дуже залежать від вашого фактичного коду навколо нього:

  1. Інжекція SQL другого порядку - якщо SQL-запит відновлюється на основі даних, отриманих із бази даних після втечі , дані об'єднуються в нерозмірні масштаби і можуть бути побічно введені SQL. Побачити
  2. Обрізання рядків - (трохи складніше) - Сценарій - у вас є два поля, скажіть ім'я користувача та пароль, і SQL об'єднує їх обоє. І в обох полях (або тільки в першому) є жорстка межа по довжині. Наприклад, ім’я користувача має обмеження до 20 символів. Скажіть, у вас є цей код:
username = left(Replace(sInput, "'", "''"), 20)

Тоді те, що ви отримуєте - це ім’я користувача, втечене, а потім підстрижене на 20 символів. Проблема тут - я приберу свою цитату до 20-го символу (наприклад, після 19-х), і ваша втеча цитата буде оброблена (у 21-му символі). Потім SQL

sSQL = "select * from USERS where username = '" + username + "'  and password = '" + password + "'"

у поєднанні з вищезгаданим неправильним іменем користувача приведе пароль, що вже знаходиться поза котируванням, і буде містити безпосередньо корисне навантаження.
3. Контрабанда Unicode - У певних ситуаціях можна передавати символ унікоду високого рівня, схожий на цитату, але це не так - доки він не потрапить у базу даних, де раптом він є . Оскільки це не цитата, коли ви її підтверджуєте, вона пройде просто ... Перегляньте попередню відповідь для отримання більш детальної інформації та посилання на оригінальне дослідження.


28

Коротше кажучи: Ніколи не роби запитів, уникаючи себе. Ви обов'язково щось не так. Натомість використовуйте параметризовані запити, або якщо ви не можете цього зробити, використовуйте наявну бібліотеку, яка робить це за вас. Немає причини робити це самостійно.


2
Що робити, якщо вам доведеться мати справу з чимось на зразок "таблиць Google Fusion", де, afaik, немає жодної бібліотеки абстракцій, яка підтримує його діалект? Що б ти запропонував?
systempuntoout

20

Я усвідомлюю, що це дуже довго після того, як було задано питання, але ..

Один із способів запустити атаку на процедуру "цитувати аргумент" - це стринг-рядка. Згідно з MSDN, у SQL Server 2000 SP4 (і SQL Server 2005 SP1) занадто довга рядок буде спокійно усічена.

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

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

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

Я рекомендую перейти з параметрами. Завжди. Просто хочу, щоб я міг застосувати це в базі даних. І як побічний ефект, ви більше шансів отримати кращі звернення до кешу, оскільки більшість висловлювань виглядають однаково. (Це, безумовно, було вірно в Oracle 8)


1
Після публікації я вирішив, що посада AviD охоплює це, і більш докладно. Сподіваюся, мій пост все ще комусь допоможе.
Jørn Jensen

10

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

Сам по собі це безпечний AFAIK. Однак, як зазначав інший відповідь, вам також може знадобитися вирішити проблему виходу із зворотної області (хоч і не при передачі запиту на SQL Server за допомогою ADO або ADO.NET, щонайменше - не можна брати участь у всіх базах даних чи технологіях).

Шнаг полягає в тому, що ви дійсно повинні бути впевнені, які рядки містять введення користувача (завжди потенційно шкідливі), а які рядки є дійсними запитами SQL. Одне з пасток - якщо ви використовуєте значення з бази даних - чи були ці значення спочатку надані користувачем? Якщо так, то їх також слід уникнути. Моя відповідь - намагатися санітувати якомога пізніше (але не пізніше!), Будуючи SQL-запит.

Однак у більшості випадків прив'язка параметрів - це саме простіше.


2
Ви все ще можете використовувати заміну параметрів, навіть якщо ви створюєте власні запити.
Нік Джонсон,

1
Ви повинні побудувати рядок оператора SQL з нуля, але все ж використовувати підстановку параметрів.
JeeBee

Ні, НІКОЛИ не будуйте свої SQL заяви з нуля.
AviD

8

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


4
І коли ви пропустите ОДНІЙ випадок на ОДНОМУ вході, ви перебуваєте в pwnd.
BryanH

4
"Деякі люди, стикаючись з проблемою, думають:" Я знаю, я буду використовувати регулярні вирази. Зараз у них дві проблеми ".
MickeyfAgain_BeforeExitOfSO

1
@mickeyf Я знаю, що це звичайні настрої, але, якщо чесно, регулярні висловлювання є надзвичайно приголомшливими, як тільки ви стикаєтесь з ними.
tom.dietrich

@ tom.dietrich Це завжди залежить від реальної життєвої ситуації. F.ex. синтаксис regexpr не є стандартним, тому загалом я б радив не використовувати regexpr у контекстах, де різні системи інтегруються для спільної роботи. Це тому, що різні двигуни regexpr оцінюють regexprs по-різному, і що ще важливіше, цей важкий факт, як правило, опускається або ігнорується, що може змусити розробників не піклуватися про ці несумісності, поки їх не покусають. Таких несумісностей багато; див. f.ex. regular-expressions.info/shorthand.html (пошук на flavorsцій сторінці).
SantiBailors

6

Як би ви не знали, це все одно погана ідея.

Як щодо чогось схожого на те, щоб уникнути цитати в рядку, як це: \ '

Ваша заміна призведе до: \ ''

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


3
Дякуємо за відповідь! Я знаю, що атака буде працювати для бази даних mySQL, але я впевнений, що MS SQL Server не сприйме зворотну косу рису як символ втечі (я спробував це). Кілька пошуків Google не виявили жодних інших символів втечі, що насправді змусило мене замислитися, чому це не працює.
Патрік

6

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

Існують способи навколо будь-якого корисного чорного списку, який ви можете придумати (і деякі білі списки також).

Пристойний запис тут: http://www.owasp.org/index.php/Top_10_2007-A2

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


6

Є два способи зробити це, без винятку, щоб бути захищеним від SQL-ін'єкцій; підготовлені заяви або праметеризовані збережені процедури


4

Якщо у вас є параметризовані запити, ви повинні їх постійно використовувати. Все, що потрібно, - це один запит проскочити через мережу, і ваша БД під загрозою.


4

Так, це має спрацювати до тих пір, поки хтось не запустить SET QUOTED_IDENTIFIER OFF і не використає подвійну цитату на вас.

Редагувати: це не так просто, як не дозволяти зловмисникові вимикати котирувані ідентифікатори:

Драйвер ODBC для Native Client SQL Server та постачальник OLE DB Native Client SQL Server для SQL Server автоматично встановлюють значення QUOTED_IDENTIFIER на УВІМКНЕНО при підключенні. Це може бути налаштовано в джерелах даних ODBC, в атрибутах підключення ODBC або у властивостях з'єднання OLE DB. За замовчуванням для SET QUOTED_IDENTIFIER вимкнено для з'єднань із додатків DB-Library.

Коли створена збережена процедура, налаштування SET QUOTED_IDENTIFIER та SET ANSI_NULLS фіксуються та використовуються для наступних викликів цієї збереженої процедури .

SET QUOTED_IDENTIFIER також відповідає параметру QUOTED_IDENTIFER ALTER DATABASE.

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

Існує маса способів, коли QUOTED_IDENTIFIER може бути вимкнений, не знаючи цього. Справді, це не подвиг курінного пістолета, який ви шукаєте, але це досить велика поверхня атаки. Звичайно, якщо ви також уникнули подвійних цитат - тоді ми знову з того, з чого почали. ;)


1
Це могло б спрацювати, але знову ж таки, як вони могли змусити цей код виконувати, коли весь вхід користувача оточений єдиними лапками? Конкретні рядки коду, які могли б ввести SQL у вищевказаний код, були б дуже корисними. Дякую!
Патрік

4

Ваш захист не вдасться, якщо:

  • запит очікує число, а не рядок
  • Існував будь-який інший спосіб представити єдиний лапок, включаючи:
    • послідовність втечі, така як \ 039
    • символом unicode

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


4

Патріку, ти додаєш поодинокі лапки навколо ВСЕХ вхідних даних, навіть числового введення? Якщо ви маєте числове введення, але не ставите навколо нього жодних лапок, значить, у вас є експозиція.


1

Який некрасивий код, який би був цей санітарій введення користувачів! Потім незграбний StringBuilder для оператора SQL. Підготовлений метод оператора призводить до набагато чистішого коду, а переваги SQL Injection - справді приємне доповнення.

Також навіщо винаходити колесо?


1

Замість того, щоб змінити одну цитату на (як це виглядає) дві одиничні лапки, чому б просто не змінити її на апостроф, цитату або повністю видалити її?

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

ПРИМІТКА. Ваш метод також передбачає, що кожен, хто працює над вашим додатком, завжди пам’ятає про необхідність очищення даних, перш ніж він потрапляє в базу даних, що, мабуть, не реально більшу частину часу.


Оголошено, оскільки відповідь не стосується питання. Питання стосується виходу рядків у SQL. Коли ви уникаєте довільної рядки (як намагається зробити запитуючий, щоб боротися з несанітованими даними), ви не можете просто замінити проблемні символи на довільні інші; що пошкоджує дані. (Крім того, одна цитата - це апостроф (принаймні в ASCII).)
andrewf

-1

Хоча ви можете знайти рішення, яке працює для рядків, для числових предикатів також потрібно переконатися, що вони лише передають цифри (проста перевірка, чи можна це розбирати як int / double / decimal?).

Це багато зайвої роботи.


-2

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


-3

Так, ви можете, якщо ...

Вивчивши тему, я вважаю, що введення даних, як ви запропонували, безпечні, але лише за цими правилами:

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

    • Програми SQL важко перевірити
  2. ви або використовуєте nvarchar/ ncharстолбцы (і префіксні рядкові літерали з N) АБО граничні значення, що входять у varchar/ charстовпці лише для символів ASCII (наприклад, викид викидання при створенні оператора SQL)

    • таким чином ви уникнете автоматичного перетворення апострофа з CHAR (700) в CHAR (39) (і, можливо, інші подібні хакі Unicode)
  3. ви завжди підтверджуєте довжину значення, щоб відповідати фактичній довжині стовпця (викидайте виключення, якщо довше)

    • в SQL Server був відомий дефект, що дозволяє обходити помилку SQL, скинуту на усічення (що призводить до безшумного усічення)
  4. ви гарантуєте, що SET QUOTED_IDENTIFIERце завждиON

    • будьте обережні, це вводиться в дію за розбір часу, тобто навіть у важкодоступних розділах коду

Виконуючи ці 4 пункти, ви повинні бути в безпеці. Якщо ви порушите будь-який з них, відкриється шлях до ін'єкції SQL.


1
Схоже, ви не прочитали всіх інших відповідей на це 8-річне запитання , оскільки будь-яка кількість цих відповідей вказує, що його метод не може зупинити ін'єкцію, якщо зловмисник просто використовує символи unicode.
Хоган

@Hogan - Я це зробив, але я думаю, що в моєму питанні є додаткова цінність. У мене є великий досвід і тестування на тому, що я написав. Я знаю, що краще використовувати параметри запиту, але я також повністю розумію ситуацію, коли хтось повинен її уникати через різні причини (наприклад, роботодавець вимагає дотримуватися колишнього способу). У цьому випадку я вважаю, що моя відповідь є дуже вичерпною і має більшу цінність, ніж відповіді, які говорять "просто не роби цього", тому що це показує шлях. Покажіть мені інші відповіді, які показують те саме, і я розглядаю питання про видалення моєї.
miroxlav

Гаразд, коли (якщо не) ваша система потрапляє в компрометацію, поверніться та видаліть цю відповідь .... або ви можете використовувати параметризований запит.
Хоган

@Hogan - У мене немає проблем це зробити :) Але в даний час я стверджую, що немає відомого способу обійти це, якщо ви будете дотримуватися 4 правил, які я опублікував. Якщо ви дійсно думаєте, що існує спосіб її подолання, тоді просто вкажіть, куди.
miroxlav

Погана порада гомбр. будь-яка інтерполяція може бути переможена.
Шейн
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.