Чому інжекція SQL не відбувається з цим запитом всередині збереженої процедури?


18

Я зробив таку збережену процедуру:

ALTER PROCEDURE usp_actorBirthdays (@nameString nvarchar(100), @actorgender nvarchar(100))
AS
SELECT ActorDOB, ActorName FROM tblActor
WHERE ActorName LIKE '%' + @nameString + '%'
AND ActorGender = @actorgender

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

EXEC usp_actorBirthdays 'Tom', 'Male; DROP TABLE tblActor'

На зображенні нижче показано, що SQL вище виконується в SSMS і результати відображаються правильно замість помилки:

введіть тут опис зображення

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


Ви пробували цеEXEC usp_actorBirthdays 'Tom', 'Male''; DROP TABLE tblActor'
MarmiK

Відповіді:


38

Цей код працює належним чином, оскільки це:

  1. Параметризовані та
  2. Не робить жодного динамічного SQL

Для того, щоб SQL Injection працювала, вам потрібно створити рядок запиту (який ви не робите), а не переводити окремі апострофи ( ') в escape-apostrophes ( '') (ті, які виводяться через вхідні параметри).

У вашій спробі передати "компрометоване" значення, 'Male; DROP TABLE tblActor'рядок - це саме те, що є звичайним рядком.

Тепер, якщо ви щось робили:

DECLARE @SQL NVARCHAR(MAX);

SET @SQL = N'SELECT fields FROM table WHERE field23 = '
          + @InputParam;

EXEC(@SQL);

тоді це може бути сприйнятливим до ін'єкції SQL, оскільки цей запит не знаходиться в поточному, попередньо проаналізованому контексті; на даний момент запит - це лише інший рядок. Таким чином, значення @InputParamможе бути '2015-10-31'; SELECT * FROM PlainTextCreditCardInfo;і те, що може представляти проблему, оскільки цей запит буде надано та виконується як:

SELECT fields FROM table WHERE field23 = '2015-10-31'; SELECT * FROM PlainTextCreditCardInfo;

Це одна (з декількох) головних причин використання збережених процедур: за своєю суттю більш захищена (ну, поки ви не обходите цю безпеку, будуючи запити, як я показав вище, не перевіряючи значення будь-яких використовуваних параметрів). Хоча якщо вам потрібно створити Dynamic SQL, кращим способом є його параметризація, використовуючи sp_executesql:

DECLARE @SQL NVARCHAR(MAX);

SET @SQL = N'SELECT fields FROM table WHERE field23 = @SomeDate_tmp';

EXEC sp_executesql
  @SQL,
  N'SomeDate_tmp DATETIME',
  @SomeDate_tmp = @InputParam;

Використовуючи цей підхід, хто - то намагається передати '2015-10-31'; SELECT * FROM PlainTextCreditCardInfo;для DATETIMEвхідного параметра отримати помилку при виконанні процедури, що. Або навіть якщо Збережена процедура прийнята @InputParameterяк NVARCHAR(100), вона повинна буде перетворитись на a DATETIME, щоб перейти в цей sp_executesqlвиклик. І навіть якщо параметр в Dynamic SQL є рядковим типом, вступаючи в процедуру зберігання, в першу чергу, будь-який єдиний апостроф автоматично переходить у подвійний апостроф.

Існує менш відомий тип атаки, при якому зловмисник намагається заповнити поле введення апострофами, таким чином, що рядок всередині збереженої процедури, який буде використовуватися для побудови динамічного SQL, але який оголошений занадто малим, не може вмістити все і виштовхує закінчується апостроф і якось закінчується правильною кількістю апострофів, щоб більше не «уникнути» всередині рядка. Це називається SQL Truncation, про який говорилося в статті журналу MSDN під назвою "Нові атаки скорочення SQL і як їх уникнути", Бала Неерумалла, але стаття більше не в Інтернеті. Випуск, що містить цю статтю - журнал MSDN за листопад 2006 року - доступний лише у вигляді довідкового файлу Windows (in .chmформат). Якщо ви завантажите його, він може не відкритися через налаштування безпеки за замовчуванням. Якщо це сталося, то клацніть правою кнопкою миші файл MSDNMagazineNovember2006en-us.chm та виберіть "Властивості". На одній із цих вкладок буде опція "Довіряти файлу цього типу" (чи тому подібному), який потрібно перевірити / включити. Натисніть кнопку "ОК", а потім спробуйте відкрити .chm файл ще раз.

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

-- Parameters:
DECLARE @UserID      INT = 37,
        @NewPassword NVARCHAR(15) = N'Any Value ....''',
        @OldPassword NVARCHAR(15) = N';Injected SQL--';

-- Stored Proc:
DECLARE @SQL NVARCHAR(MAX),
        @NewPassword_fixed NVARCHAR(15) = REPLACE(@NewPassword, N'''', N''''''),
        @OldPassword_fixed NVARCHAR(15) = REPLACE(@OldPassword, N'''', N'''''');

SELECT @NewPassword AS [@NewPassword],
       REPLACE(@NewPassword, N'''', N'''''') AS [REPLACE output],
       @NewPassword_fixed AS [@NewPassword_fixed];
/*
@NewPassword          REPLACE output          @NewPassword_fixed
Any Value ....'       Any Value ....''        Any Value ....'
*/

SELECT @OldPassword AS [@OldPassword],
       REPLACE(@OldPassword, N'''', N'''''') AS [REPLACE output],
       @OldPassword_fixed AS [@OldPassword_fixed];
/*
@OldPassword          REPLACE output          @OldPassword_fixed
;Injected SQL--       ;Injected SQL--         ;Injected SQL--
*/

SET @SQL = N'UPDATE dbo.TableName SET [Password] = N'''
           + @NewPassword_fixed + N''' WHERE [TableNameID] = '
           + CONVERT(NVARCHAR(10), @UserID) + N' AND [Password] = N'''
           + @OldPassword_fixed + N''';';

SELECT @SQL AS [Injected];

Ось тепер динамічний SQL, який потрібно виконати:

UPDATE dbo.TableName SET [Password] = N'Any Value ....'' WHERE [TableNameID] = 37 AND [Password] = N';Injected SQL--';

Той самий динамічний SQL у більш читаному форматі:

UPDATE dbo.TableName SET [Password] = N'Any Value ....'' WHERE [TableNameID] = 37 AND [Password] = N';

Injected SQL--';

Виправити це легко. Виконайте одне з наступних дій:

  1. НЕ ВИКОРИСТОВУЙТЕ ДИНАМІЧНИЙ SQL БЕЗ ЗАБЕЗПЕЧНО АБСОЛЮТНО ! (Я перелічу це першим, тому що це дійсно має бути першим, що слід розглянути).
  2. Належне розмір локальної змінної (тобто повинен бути вдвічі більшим за вхідний параметр, на випадок, якщо всі передані символи є одинарними лапками).
  3. Не використовуйте локальну змінну для зберігання "фіксованого" значення; просто вкладіть REPLACE()безпосередньо у створення Dynamic SQL:

    SET @SQL = N'UPDATE dbo.TableName SET [Password] = N'''
               + REPLACE(@NewPassword, N'''', N'''''') + N''' WHERE [TableNameID] = '
               + CONVERT(NVARCHAR(10), @UserID) + N' AND [Password] = N'''
               + REPLACE(@OldPassword, N'''', N'''''') + N''';';
    
    SELECT @SQL AS [No SQL Injection here];

    Динамічний SQL більше не порушений:

    UPDATE dbo.TableName SET [Password] = N'Any Value ....''' WHERE [TableNameID] = 37 AND [Password] = N';Injected SQL--';

Примітки про приклад Trunction вище:

  1. Так, це дуже надуманий приклад. Внести в дію лише 15 символів не так багато. Звичайно, це може DELETE tableNameбути руйнівним, але менше шансів додати користувача заднього дверей або змінити пароль адміністратора.
  2. Цей тип атаки, ймовірно, вимагає знання коду, назв таблиць тощо. Менш ймовірно, що це робитиме випадковий незнайомець / скрипт-малюк, але я працював у місці, на яке напав досить засмучений колишній співробітник, який знав про вразливість на одній конкретній веб-сторінці, про яку ніхто інший не знав. Це означає, що іноді зловмисники мають інтимні знання про систему.
  3. Зрозуміло, перезавантаження пароля кожного, ймовірно, буде розслідувано, що може призвести до того, що компанія може відмовитись від того, що трапляється напад, але це може все-таки забезпечити достатньо часу для введення в користування заднього дверей або, можливо, пізніше отримати додаткову інформацію для використання / використання.
  4. Навіть якщо цей сценарій здебільшого є академічним (тобто, мабуть, не відбудеться в реальному світі), все одно це неможливо.

Для отримання більш детальної інформації, що стосується інжекцій SQL (охоплює різні RDBMS та сценарії), дивіться наступне з проекту безпеки веб-застосунку (OWASP):
Тестування на ін'єкцію SQL

Відповідна відповідь на переповнення стека на ін'єкцію SQL та обрізання SQL:
Наскільки безпечним є T-SQL після заміни символу 'escape?


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

1
@Ravi Я знайшов посилання, але воно більше не потрапляє до статті, оскільки всі вони тепер архівовані. Але я додав інформацію та корисні посилання, і я все ще намагаюся знайти статтю в цих архівах.
Соломон Руцький

1
Дякую серцузькому, я прочитаю статтю OWASP та тести на ін’єкції. Якщо я правильно пам’ятаю, «mutillidae», вразливий веб-додаток для тестування безпеки, має інжекцію SQL, яку я виконував у коледжі за допомогою рядка «АБО 1 = 1», який у mutillidae призвів до того, що я ввійшов у веб-додаток як адміністратор I думати. Саме тоді я вперше ознайомився з ін'єкцією SQL.
Раві

1
Я також не в змозі переглянути файл .chm, але вдячний вам за цю ідеальну відповідь та за всі корисні посилання, включаючи посилання з stackoverflow та одне з OWASP. Я прочитав це сьогодні і багато чого навчився з цього.
Раві

2

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

Я писав про це на сайті: http://blogs.lobsterpot.com.au/2015/02/10/sql-injection-the-golden-rule/


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