Как Dapper помогает защитить от инъекций SQL? Я тестирую различные технологии DAL и должен выбрать один для обеспечения безопасности нашего сайта. Я склоняюсь к Dapper (http://code.google.com/p/dapper-dot-net/), но вам нужна помощь в ознакомлении с безопасностью.
Инъекции Dapper и SQL
Ответ 1
Как Dapper помогает защитить от инъекций SQL?
Это делает действительно, действительно простым в использовании полностью параметризованный доступ к данным, без необходимости связывать входные данные. В частности, поскольку вам не нужно перескакивать через множество "добавить параметр", установить тип параметра, проверить значение "null", поскольку ADO.NET имеет sucky null-handling, rinse/repeat для 20 параметров ", делая обработку параметров глупо удобно. Он также превращает ряды в объекты очень просто, избегая соблазна использовать DataTable
... все выигрывают.
Из комментариев:
Еще одно... что делает dapper на самом деле помогает?
Чтобы ответить, давайте возьмем пример из ответа marc_s и напишем его по-старому, считая, что все, с чего мы должны начать, - это connection
. Тогда:
List<Dog> dogs = new List<Dog>();
using(var cmd = connection.CreateCommand()) {
cmd.CommandText = "select Age = @Age, Id = @Id";
cmd.Parameters.AddWithValue("Age", DBNull.Value);
cmd.Parameters.AddWithValue("Id", guid);
using(var reader = cmd.ExecuteReader()) {
while(reader.Read()) {
int age = reader.ReadInt32("Age");
int id = reader.ReadInt32("Id");
dogs.Add(new Dog { Age = age, Id = id });
}
while(reader.NextResult()) {}
}
}
за исключением того, что я чрезмерно упрощен, так как он также затрагивает широкий спектр вопросов, таких как:
- нулевое обращение параметров
- Обработка имен столбцов результатов
- с использованием индексов порядковых столбцов
- адаптация к структурным изменениям таблицы и типа
- преобразование данных столбцов результатов (между различными примитивами, строками, перечислениями и т.д.)
- специальная обработка сценария oh-so-common "в этом списке"
- для "execute", специальная обработка "примените это отдельно к списку входов"
- избегая глупых опечаток
- сокращение обслуживания кода
- обработка нескольких сеток
- обработка нескольких объектов, возвращаемых по горизонтали в одной сетке
- работает с произвольными поставщиками ADO.NET(подсказка:
AddWithValue
редко существует)- включая определенную поддержку таких вещей, как Oracle, для которой требуется дополнительная настройка
- отлично работает с ADO.NET decoratos, такими как "мини-профайлер"
- встроенная поддержка как буферизированных (подходит для небольших и умеренных данных, минимизирует длительность команд), так и non-bufferesd (подходит для больших данных, минимизирует использование памяти).
- оптимизируется людьми, которые заботятся о производительности и знают "совсем немного" о доступе к данным и метапрограмме
- позволяет использовать ваш выбор POCO/DTO/anon-type/whatever для параметра и выхода
- позволяет использовать либо
dynamic
(для нескольких столбцов), либо примитивы и т.д. (для одного столбца), когда вывод не требует генерации POCO/DTO - избегать накладных расходов сложных полностью типизированных ORM, таких как EF
- избежать накладных расходов слабых типизированных слоев, например
DataTable
- открытие и закрытие соединений как необходимо
- и широкий спектр других распространенных ошибок
Ответ 2
Вам просто нужно использовать параметризованные запросы, как всегда. Поскольку Dapper - это всего лишь "крошечное" (и довольно тонкое) расширение до "сырого" SQL и ADO.NET - просто используйте параметризованные запросы ADO.NET и параметры подачи.
См. этот образец с сайта Dapper-Dot-Net:
var dog = connection.Query<Dog>("select Age = @Age, Id = @Id",
new { Age = (int?)null, Id = guid });
SQL-запрос использует параметры - и вы отправляете их в запрос "Dapper".
Подводя итог: использование Dapper само по себе не защищает от SQL-инъекций как таковое - используя параметризованные запросы ADO.NET/SQL, однако (и эти запросы абсолютно поддерживаются Dapper, никаких проблем вообще)
Ответ 3
Да, в первую очередь каждый разработчик должен обеспечить безопасность бизнес-транзакции.
Для этого я всегда предпочитаю использовать storeprocude с dapper, а также метод обтекания для проверки storeprocedure, чтобы предотвратить нежелательные запросы и слова:
private static bool IsStoredProcedureNameCorrect(string storedProcedureName)
{
if (string.IsNullOrEmpty(storedProcedureName))
{
return false;
}
if (storedProcedureName.StartsWith("[") && storedProcedureName.EndsWith("]"))
{
return Regex.IsMatch(storedProcedureName,
@"^[\[]{1}[A-Za-z0-9_]+[\]]{1}[\.]{1}[\[]{1}[A-Za-z0-9_]+[\]]{1}$");
}
return Regex.IsMatch(storedProcedureName, @"^[A-Za-z0-9]+[\.]{1}[A-Za-z0-9]+$");
}
А также используйте валидатор для предотвращения нежелательных запросов в качестве параметров:
public static partial class Validator
{
private static readonly string[] Expressions = {
@"^.*((?i)select).*((?i)from).*$",
@"^.*((?i)insert into).*$",
@"^.*((?i)update).*((?i)set).*$",
@"^.*((?i)delete from).*$",
@"^.*((?i)create database).*$",
@"^.*((?i)create table).*$",
@"^.*((?i)create procedure).*$",
@"^.*((?i)create index).*$",
@"^.*((?i)alter database).*$",
@"^.*((?i)alter table).*$",
@"^.*((?i)alter procedure).*$",
@"^.*((?i)alter index).*$",
@"^.*\b((?i)exec(ute)?)\b.*$",
@"^.*((?i)shutdown with nowait).*$",
@"^.*((?i)waitfor delay).*$",
@"^.*((?i)drop table).*$"
};
public static bool DoesContainQuery(string input)
{
var inLowerCase = input.ToLower();
return Expressions.Any(expression => Regex.IsMatch(inLowerCase, expression));
}
public static string ReplaceSqlCharacter(string parameter)
{
parameter = parameter.Replace(";", "").Replace("[", "").Replace("]", "").Replace("--", "")
.Replace("_xp", "").Replace(@"/*", "").Replace(@"*/", "").Replace("@@", "");
return parameter;
}
}
Вы также можете увидеть мой подробный ответ здесь