FromSql (): запрос на построение строки из списка строк для предотвращения внедрения - PullRequest
0 голосов
/ 15 апреля 2019

Я строю поиск SQL в EF Core.Microsoft рекомендует не заключать строку в строку, поскольку она оставляет приложение уязвимым для внедрения SQL, как подробно описано в документации Microsoft: https://docs.microsoft.com/en-us/ef/core/querying/raw-sql.

Всегда использовать параметризацию для необработанных запросов SQL: В дополнение к проверке пользовательского ввода всегдаиспользуйте параметризацию для любых значений, используемых в необработанном запросе / команде SQL.API-интерфейсы, которые принимают необработанную строку SQL, такую ​​как FromSql и ExecuteSqlCommand, позволяют легко передавать значения в качестве параметров.Перегрузки FromSql и ExecuteSqlCommand, которые принимают FormattableString, также позволяют использовать синтаксис интерполяции строк таким образом, который помогает защитить от атак внедрения SQL.

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

Информация, хранящаяся в этой базе данных, не являетсячувствительный, но, очевидно, я не хотел бы оставлять уязвимую базу данных.

У меня есть параметр List<string> searchTerms, который мне нужно перебрать и построить запрос на основе этого списка.

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

var query = String.Format("SELECT ... where MySqlField like '%{0}%'", searchTerm[0]);

for (int i = 1; i < searchTerm.Count(); i++)
{
    query += String.Format(" and MySqlField like '%{0}%'", searchTerm[i]);
}

var results = context.MySqlTable.FromSql(query);

Даже если я использую интерполяцию, будет ли здесь достаточной дополнительная проверка?Я что-то упустил?

Есть ли запрос linq, который может сделать то же самое со списком?

Ответы [ 4 ]

1 голос
/ 15 апреля 2019

В данный момент я не могу проверить это, поэтому я сообщаю вам об этом подходе

List<string> ph = new List<string>();
int count = 0;
foreach(string s in searchTerm)
{
    ph.Add($"MySqlField LIKE '%{{{count}}}%'");
    count++;
}

if(count > 0)
    query = query + " WHERE " + string.Join(" OR ", ph);
var results = context.MySqlTable.FromSql(query, searchTerm.ToArray());

И хотя это похоже на подход с конкатенацией строк, мы можем прочитать в документах

Хотя это может выглядеть как синтаксис String.Format, предоставленное значение помещается в параметр, а сгенерированное имя параметра вставляется в том месте, где был указан заполнитель {0}.

1 голос
/ 15 апреля 2019

Есть несколько вариантов:

  1. Передайте свои значения в XML (или JSON, если используете более новый SQL Server), а затем напишите статический запрос XML / JSON.

  2. создать временную таблицу, вставить все значения поиска во временную таблицу и затем выполнить статический запрос.

0 голосов
/ 15 апреля 2019

Ваш код должен быть достаточно хорош с небольшой модификацией:

var query = String.Format("SELECT ... where 1=1 ");

for (int i = 0; i < searchTerm.Count(); i++)
{

    query += $" and MySqlField like '%'+{{{i}}}+'%'";
}

var results = context.MySqlTable.FromSql(query, searchTerm.ToArray());
0 голосов
/ 15 апреля 2019

Я бы порекомендовал заглянуть в LINQ, если вы используете EF.Использование необработанной строки sql не очень хорошая идея как для безопасности, так и для производительности.LINQ предоставляет надежный способ выполнения запросов.Просто будьте осторожны с тем, как вы пишете свои запросы, так как LINQ может слишком усложнить их.

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/

РЕДАКТИРОВАТЬ:

Я пропустил последнюю строку вашего сообщения,Извините, следующее должно помочь вам встать на правильный путь:

for (var item in searchTerms) {
    query = query.Where(w => w.MySqlField.Contains(item.Value));
}
...