Достаточно ли параметров для предотвращения инъекций Sql?
Я проповедовал как моим коллегам, так и здесь, в SO, о правильности использования параметров в запросах SQL, особенно в приложениях.NET. Я даже зашел так далеко, что обещал им защиту от атак SQL-инъекций.
Но я начинаю задумываться, правда ли это на самом деле. Существуют ли какие-либо известные атаки SQL-инъекций, которые будут успешными в отношении параметризованного запроса? Вы можете, например, отправить строку, которая вызывает переполнение буфера на сервере?
Есть, конечно, и другие соображения, чтобы гарантировать безопасность веб-приложения (например, дезинфекция пользовательского ввода и все такое), но теперь я думаю о SQL-инъекциях. Я особенно заинтересован в атаках на MsSQL 2005 и 2008, поскольку они являются моими основными базами данных, но все базы данных интересны.
Изменить: чтобы уточнить, что я имею в виду под параметрами и параметризованными запросами. Используя параметры, я имею в виду использование "переменных" вместо построения запроса SQL в строке.
Так что вместо этого:
SELECT * FROM Table WHERE Name = 'a name'
Мы делаем это:
SELECT * FROM Table WHERE Name = @Name
а затем установите значение параметра @Name в объекте запроса / команды.
9 ответов
Заполнителей достаточно, чтобы предотвратить инъекции. Возможно, вы все еще открыты для переполнения буфера, но это совершенно другой вид атаки, чем инъекция SQL (вектор атаки будет не синтаксисом SQL, а двоичным). Поскольку все передаваемые параметры будут экранированы должным образом, злоумышленник не сможет передать данные, которые будут обрабатываться как "живой" SQL.
Вы не можете использовать функции внутри заполнителей, и вы не можете использовать заполнители в качестве имен столбцов или таблиц, потому что они экранируются и заключаются в кавычки как строковые литералы.
Однако, если вы используете параметры как часть конкатенации строк внутри вашего динамического запроса, вы по-прежнему уязвимы для внедрения, потому что ваши строки не будут экранированы, но будут литеральными. Использование других типов для параметров (например, целое число) безопасно.
Тем не менее, если вы используете ввод, чтобы установить значение что-то вроде security_level
Тогда кто-то может просто стать администратором в вашей системе и получить всеобщее право. Но это только базовая проверка ввода и не имеет ничего общего с SQL-инъекцией.
Нет, существует риск внедрения SQL-кода каждый раз, когда вы интерполируете непроверенные данные в SQL-запрос.
Параметры запроса помогают избежать этого риска, отделяя литеральные значения от синтаксиса SQL.
'SELECT * FROM mytable WHERE colname = ?'
Это нормально, но есть и другие цели интерполяции данных в динамический запрос SQL, который не может использовать параметры запроса, потому что это не значение SQL, а имя таблицы, имя столбца, выражение или какой-либо другой синтаксис.
'SELECT * FROM ' + @tablename + ' WHERE colname IN (' + @comma_list + ')'
' ORDER BY ' + @colname'
Не имеет значения, используете ли вы хранимые процедуры или выполняете динамические SQL-запросы непосредственно из кода приложения. Риск все еще там.
Средство защиты в этих случаях - использовать FIEO по мере необходимости:
Входные данные фильтра: убедитесь, что данные выглядят как допустимые целые числа, имена таблиц, имена столбцов и т. Д., Прежде чем их интерполировать.
Выход Escape: в данном случае "выход" означает помещение данных в SQL-запрос. Мы используем функции для преобразования переменных, используемых в качестве строковых литералов в выражении SQL, чтобы экранировать кавычки и другие специальные символы внутри строки. Мы также должны использовать функции для преобразования переменных, которые будут использоваться в качестве имен таблиц, имен столбцов и т. Д. Что касается другого синтаксиса, такого как динамическое написание целых выражений SQL, это более сложная проблема.
Похоже, что в этой теме есть некоторая путаница с определением "параметризованного запроса".
- 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();
}
Любой параметр sql строкового типа (varchar, nvarchar и т. д.), используемый для построения динамического запроса, все еще уязвим
в противном случае преобразование типа параметра (например, в int, десятичное число, дату и т. д.) должно исключить любые попытки внедрить sql через параметр
РЕДАКТИРОВАТЬ: пример, где параметр @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-сервере нет возможных эксплойтов в виде ошибок, но ничто не гарантирует этого.
Ваши данные небезопасны, если вы используете динамический sql в любой форме или форме, потому что разрешения должны быть на уровне таблицы. Да, вы ограничили тип и количество инъекционных атак из этого конкретного запроса, но не ограничили доступ, который пользователь может получить, если он или она находит путь в систему, и вы полностью уязвимы для внутренних пользователей, получающих доступ к тому, что им не следует делать в приказ о мошенничестве или краже личной информации для продажи. Динамический SQL любого типа - опасная практика. Если вы используете нединамические хранимые процедуры, вы можете устанавливать разрешения на уровне процесса, и ни один пользователь не может делать ничего, кроме того, что определено процедурами (конечно, кроме системных администраторов).
Вы можете запустить динамический 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-файле, извлекается позднее для других целей).
Возможно, что хранимый процесс уязвим к особым типам SQL-инъекций через переполнение / усечение, см.: Инъекция, разрешенная усечением данных здесь: