9

У нас есть тонна хранимых процедур SQL Server, основанных на динамическом SQL.Как очистить динамический SQL в SQL Server - предотвратить SQL-инъекцию

Параметры хранимой процедуры используются в динамическом выражении SQL.

Нам нужна стандартная функция проверки внутри этих хранимых процедур для проверки этих параметров и предотвращения внедрения SQL.

Предположим, у нас есть эти ограничения:

  1. Мы не можем переписать процедуры, чтобы не использовать динамический SQL

  2. Мы не можем использовать sp_OACreate и т.д., использовать регулярные выражения для проверки.

  3. Мы не можем изменить приложение, которое вызывает хранимую процедуру для проверки параметров до их передачи в хранимую процедуру.

Есть ли набор символов, которые мы можем отфильтровать, чтобы гарантировать, что мы не подвержены SQL-инъекции?

+0

ouch. обычно это 3), который должен быть изменен для предотвращения внедрения SQL. Помните, что это «SQL Injection», а не «SQL Rejection». Как только он попадает в БД, он уже должен быть очищен. Но если вы говорите, что вы не можете изменить приложение, то я думаю, вы не можете. Заинтересованы в ответах. – RPM1984

ответ

10

Я считаю, что есть три различных случая, которые вы должны беспокоиться о:

  • строк (ничего, что требует кавычек): '''' + replace(@string, '''', '''''') + ''''
  • имена (ничего, где кавычки не допускается): quotename(@string)
  • вещи, которые не могут быть указаны: это требует Whitelisting

Примечание: Всех в переменных строках (char, varchar, nchar, nvarchar и т.д.), что происходит из контролируемого пользователя источников должны использовать один из указанных выше способов. Это означает, что даже те, которые вы ожидаете быть числами, цитируются, если они хранятся в строковых переменных.

Для получения более подробной информации см Microsoft Magazine (Устаревшая ссылка: 2016-10-19).

Вот пример использования всех трех методов:

EXEC 'SELECT * FROM Employee WHERE Salary > ''' + 
    REPLACE(@salary, '''', '''''') + -- replacing quotes even for numeric data 
    ''' ORDER BY ' + QUOTENAME(@sort_col) + ' ' + -- quoting a name 
    CASE @sort_dir WHEN 'DESC' THEN 'DESC' END  -- whitelisting 

отметить также, что при этом всех операциях со строками встроенными в EXEC заявления нет озабоченности в связи с проблемами усечения. Если вы назначаете промежуточные результаты переменным, вы должны должны убедиться, что переменные достаточно велики, чтобы удерживать результаты. Если вы делаете SET @result = QUOTENAME(@name), вы должны определить @result, чтобы содержать не менее 258 символов (2 * 128 + 2). Если вы делаете SET @result = REPLACE(@str, '''', ''''''), вы должны определить @result, чтобы быть в два раза размером @str (предположим, что каждый символ в @str может быть цитатой). И, конечно, строковая переменная, содержащая конечный оператор SQL, должна быть достаточно большой, чтобы содержать все статические SQL плюс все переменные результата.

+0

Я согласен с этим, это полностью зависит от того, что SQL строится. –

2

OWASP содержит информацию об этой стратегии. Он всегда должен быть вариантом последних отчаянным (как описан в статье я ссылаюсь), но если это единственный вариант ...

http://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet

цитата из статьи о его будучи last- опция канава

Однако эта методика является хрупким по сравнению с использованием параметризованных запросов. Этот метод должен быть только с осторожностью использовать модифицированный код экономичным способом. Приложения, созданные с нуля, или Приложения, требующие низкого риска Допуск должен быть построен или , переписанный с использованием параметризованных запросов.

По сути, аргумент против такого подхода, даже если вы избежите всех известных плохих входных данных, нет никакой гарантии, что кто-то не придумает способ обойти его в будущем.

Однако, чтобы ответить на ваш вопрос конкретно ...

список символов, чтобы избежать в статье я связан выше.

Редактировать Как уже отмечалось, статья не содержит очень хороших ссылок. Однако для SQL Server это делает: http://msdn.microsoft.com/en-us/library/ms161953.aspx

Обратите внимание, что список символов, которые нужно удалить, зависит от платформы БД, но похоже, что вы используете SQL Server, поэтому это должно быть актуально. .

Цитата из статьи ниже:

Фильтрация ввода также может быть полезным в защите от инъекции SQL путем удаления управляющих символов.Однако из-за большого количества символов, которые могут создавать проблемы, это не надежная защита. В следующем примере выполняется поиск разделителя символьной строки.

private string SafeSqlLiteral(string inputSQL) 
{ 
    return inputSQL.Replace("'", "''"); 
} 

LIKE Клаусов

Обратите внимание, что если вы используете LIKE условие, подстановочные символы по-прежнему должны быть экранированы:

s = s.Replace("[", "[[]"); 
s = s.Replace("%", "[%]"); 
s = s.Replace("_", "[_]"); 
+1

-1: В статье не сказано, какие символы следует избегать для MS SQL Server. Он просто ссылается на другую статью, которая не делает очевидным, какие символы следует избегать. – Gabe

+0

Вы правы. Редактирование моего ответа. – David

3

Это очень неприятная проблема, ее не проблема вы хотите решить, но вот тривиальный случай, который работает, (рецензенты, пожалуйста, дайте мне знать, если я пропустил дело, это связано с NO гарантирует)

create proc Bad 
    @param nvarchar(500) 
as 

exec (N'select ''' + @param + N'''') 

go 

-- oops injected 
exec Bad 'help'' select ''0wned!'' select ''' 

go 

create proc NotAsBad 
    @param nvarchar(500) 
as 

declare @safish nvarchar(1000), @sql nvarchar(2000) 
set @safish = replace(@param, '''', '''''') 

set @sql = N'select ''' + @safish + N'''' 

exec (@sql) 

go 

-- this kind of works, but I have not tested everything 
exec NotAsBad 'help'' select ''0wned!'' select ''' 
+0

+1, я никогда не видел ничего, чтобы предположить, что это не сработает. – Gabe

+1

На мой взгляд, запуск любого динамического SQL с использованием чего-либо другого, кроме sp_executesql, со всеми значениями, переданными как параметры, является просто чистой халатности. –

+0

Все еще уязвим. Предположим, что тело NotAsBad содержит следующее: set @sql = N'select * from '+ @ safish .... если пользователь может угадать имя таблицы, которую они могут отправить @param =' tablename; drop database xyz; - ' – frankadelic

6

тривиальные случаи могут быть исправлены QUOTENAME и REPLACE:

set @sql = N'SELECT ' + QUOTENAME(@column) + 
    N' FROM Table WHERE Name = ' + REPLACE(@name, '''', ''''''); 

Хотя QUOTENAME может быть использован на литералах тоже добавить одиночные кавычки и заменить одиночные кавычки с двойными одинарными кавычками, потому что он обрежет вклад 128 символов не рекомендуется.

Но это только верхушка айсберга.Существуют множественные имена (dbo.table), которые вам необходимо соблюдать: цитирование multipartname приведет к недопустимому идентификатору [dbo.table], его нужно разобрать и разбить (используя PARSENAME), затем правильно указывается в [dbo].[table].

Другой проблемой являются усекающие атаки, которые могут произойти, даже если вы делаете тривиальный REPLACE на литералах, см. New SQL Truncation Attacks And How To Avoid Them.

Проблема SQL Injection никогда не может быть решена с помощью одной магической функции, установленной для каждой процедуры. Это похоже на запрос «Я хочу функцию, которая заставит мой код работать быстрее». Предотвращение инъекционных атак - и конец-конец игра, которая требует кодирования дисциплины полностью через, его нельзя просто добавить в качестве запоздалой мысли. Лучше всего проверить каждую отдельную процедуру и проанализировать код T-SQL по очереди с открытыми глазами для уязвимостей, а затем устранить проблемы по мере их нахождения.

+0

Я рекомендую * не * использовать 'PARSENAME', потому что он предназначен для использования в уже цитируемых именах. Если ваш пользователь говорит вам, что хочет получить данные из 'secret..table', вы хотите запросить' [secret..table] 'и получить сообщение об ошибке. Вы не хотите, чтобы он мог запросить '[secret] .. [table]'! – Gabe

+0

На мой взгляд, запуск любого динамического SQL с использованием чего-либо другого, кроме sp_executesql, со всеми значениями, переданными как параметры, является просто чистой халатности. –

0

Можете ли вы получить SQL CLR может быть очень полезно - вы можете хотя бы использовать его для написания гораздо более эффективной санитарии, чем это можно сделать с помощью T-SQL. В перфективном мире вы можете полностью заменить сохраненные procs параметризованными утверждениями и другими более прочными структурами.

+0

К сожалению, я не могу использовать CLR из-за ограничений DBA. – frankadelic

4

С этими ограничениями вы довольно ввернуты.

Вот два варианта, которые могут дать вам некоторое направление:

  1. Используйте белый список валидатор/анализатор, который принимает только запросы, в формате и с ключевыми словами и таблицами, которые, как ожидаются. Вероятно, это будет работать только с очень хорошим синтаксическим анализатором SQL, который действительно понимает синтаксис.

  2. Выполнение запросов в ограниченной среде. Например, используйте учетную запись пользователя с очень ограниченными правами. Например, разрешать (читать) доступ к определенным представлениям, которые никогда не будут возвращать конфиденциальные данные и запрещать доступ ко всем другим представлениям, всем хранимым процедурам, функциям и таблицам. Еще безопаснее выполнять эти запросы на другом сервере базы данных. Также не забудьте отключить команду OPENROWSET.

Пожалуйста, обратите внимание на следующее:

  1. Когда вы принимаете все запросы, за исключением тех, которые имеют недействительные ключевые слова, вы, безусловно, не получится, потому что черный список всегда терпит неудачу. Особенно с таким сложным языком, как SQL.

  2. Не забывайте, что разрешение динамического SQL из источников, которым вы не можете доверять, является злым в своем самом чистом смысле, даже когда вы используете эти советы, потому что время от времени обнаруживаются bugs, которые могут быть злоупотреблены отправлением специально созданного SQL к серверу. Поэтому, даже если вы применяете эти советы, риск все еще существует.

  3. Когда вы решите пойти с решением, которое позволяет динамический SQL. Пожалуйста, не думайте, что вы можете придумать безопасное решение, особенно если вы пытаетесь защитить конфиденциальные бизнес-данные. Нанять специалиста по безопасности сервера баз данных, чтобы помочь вам в этом.

-1

Существует еще один подход, который может возможно работать, хотя это зависит от того, какие символы разрешены в параметрах хранимой процедуры. Вместо того, чтобы избегать неприятных символов, которые могут быть использованы для SQL-инъекции, вместо этого удалите символы. Например, если у вас есть этот SP:

create procedure dbo.MYSP(@p1 varchar(100)) 
as begin 
    set @p1 = Replace(@p1, '''',' '); -- Convert single quotes to spaces 
    set @p1 = Replace(@p1, ';', ' '); 
    set @p1 = Replace(@p1, '--', ' ');  
    set @p1 = Replace(@p1, '/*', ' ');  
    set @p1 = Replace(@p1, '*/', ' ');  
    set @p1 = Replace(@p1, 'xp_', ' ');  
    ... 
end; 

Вы можете заменить любые одиночные кавычки пробелами или пустой строкой. Этот подход также может использоваться для замены символов комментария, таких как/* */-, с использованием более команд Replace (как я только что показал выше). Но обратите внимание, что этот подход будет работать только в том случае, если вы никогда не ожидаете, что эти символы будут нормально работать, и это зависит от вашего приложения.

Обратите внимание на набор заменяемых символов основан на https://msdn.microsoft.com/en-us/library/ms161953(SQL.105).aspx

+0

SQL-инъекция не называется «Single Quote injection». По причине. –

+0

Я не знаком с «инъекцией одной кавычки», метод, который я только что описал, является одним из методов защиты от SQL Injection и основан на статье Microsoft, на которую я ссылался выше. Я не понимаю, почему вы проголосовали за этот ответ. – Ubercoder

+0

, затем ознакомьтесь с основами безопасности и узнайте, почему какой-либо подход, основанный на черных списках, преднамеренно испорчен –

2

Есть набор символов можно отфильтровать, чтобы гарантировать, что мы не восприимчивы к SQL инъекций?

NO

SQL инъекция не называется "Certain набора символов для инъекций", и по причине. Фильтрация определенного символа может усложнить конкретный эксплойт, но не предотвращает сам SQL-инъекцию. Чтобы использовать SQL-инъекцию, нужно написать SQL. И SQL не ограничивается несколькими специальными символами.

Смежные вопросы