Запретить SQL-инъекцию в предложении ORDER BY
На нашем уровне доступа к БД мы создаем динамическое создание запросов. Например, у нас есть следующий способ построения части предложения ORDER BY
:
protected string BuildSortString(string sortColumn, string sortDirection, string defaultColumn)
{
if (String.IsNullOrEmpty(sortColumn))
{
return defaultColumn;
}
return String.Format("{0} {1}", sortColumn, sortDirection);
}
Проблема заключается в том, что sortColumn
и sortDirection
оба происходят извне как строки, поэтому, конечно, что-то нужно сделать, чтобы предотвратить возможные атаки на инъекции. Кто-нибудь знает, как это можно сделать?
Ответы
Ответ 1
Если у вас есть, чтобы иметь дело со строками, то белым списком будет ваш лучший выбор. Во-первых, sortDirection
должен быть довольно тривиальным для белого списка: без учета регистра по сравнению с "asc"
/"desc"
, и вы должны быть установлены. Для остальных моим предпочтением будет белый список для известных столбцов, возможно, путем передачи ожидаемого Type
для данных и проверки. Но при абсолютном пинче вы можете ограничить регулярным выражением (скажем), чтобы они были строго альфа-числовыми (в диапазоне az, AZ, 0-9 - возможно, подчеркивание при необходимости) - и затем добавьте []
, т.е.
return string.Format("[{0}] {1}", sortColumn, sortDirection);
Но: строгий белый список известных столбцов будет намного лучше, как и перечисление для направления.
Ответ 2
Другое решение, если вы можете изменить свой метод, чтобы принять int
вместо параметров string
.
protected string BuildSortString(int sortColumn, int sortDirection, string defaultColumn)
{
if (String.IsNullOrEmpty(sortColumn))
{
return defaultColumn;
}
//sortdirection 0-> "ASC" else "DESC"
//sorColumn 1 for your firstcolumn, 2 for your second column etc.
return String.Format("{0} {1}", sortColumn, sortDirection==0? " ASC " : " DESC ");
}
Удачи.
Ответ 3
Вы можете сделать это, используя большой оператор CASE, в котором вы переключаетесь на основе имени и направления прошедшего столбца. Здесь есть ответ на этот вопрос. Вы будете смотреть на код вроде:
SELECT
*
FROM
My_Table
WHERE
Whatever = @something
ORDER BY
CASE @sort_order
WHEN 'ASC' THEN
CASE @order_by
WHEN 'surname' THEN surname
WHEN 'forename' THEN forename
WHEN 'fullname' THEN fullname
ELSE surname
END
ELSE '1'
END ASC,
CASE @sort_order
WHEN 'DESC' THEN
CASE @order_by
WHEN 'surname' THEN surname
WHEN 'forename' THEN forename
WHEN 'fullname' THEN fullname
ELSE surname
END
ELSE '1'
END DESC
Ответ 4
Решение: cmd.Parameters или EscapedString, но я предпочитаю cmd.Parameters(всегда работайте, и вам нравятся ожидаемые исключения)
пример:
cmd.CommandText = "SELECT UNIQUE_ID FROM userdetails WHERE USER_ID IN (?, ?)";
cmd.Parameters.Add("?ID1", OdbcType.VarChar, 250).Value = email1;
cmd.Parameters.Add("?ID2", OdbcType.VarChar, 250).Value = email2;
Использование подготовленных операторов с параметрами помогает защитить от SQL в большинстве случаев, когда вы в противном случае интерполировали бы ненадежный контент в строку, а затем выполнить строку как SQL выражение.
Но параметр запроса заменяет одно значение. Вы не можете использовать параметр запроса в качестве замены имени динамической таблицы, столбец имя, список значений (например, для предиката IN()), выражений или SQL ключевые слова.
В этих случаях вы можете использовать такие методы, как фильтрация или белый список поэтому вы не интерполируете ненадежный контент в свои строки SQL.
Фильтрация - это то, где вы снимаете любые символы, которые могли бы вызвать беда. Если вы знаете, что имя динамического столбца должно быть буквенно-цифровые символы, а затем применить фильтр к вашей переменной до используя его в SQL. Или просто отклоните переменную, если она не соответствует регулярное выражение, подобное /^ [A-Za-z0-9] * $/
Ответ 5
Вы можете сделать что-то вроде этого:
public string BuildSortString(string sortColumn, SortDirection direction, string defaultColumn)
{
string sortDirection = direction.ToString();
if (String.IsNullOrEmpty(sortColumn))
{
return VerifyColumn(defaultColumn);
}
return String.Format("{0} {1}", VerifyColumn(sortColumn), sortDirection);
}
private string VerifyColumn(string column)
{
switch (column) // fill this with a whitelist of accepted columns
{
case "some_column":
return column;
}
return String.Empty; // the column must be invalid (do whatever you want here)
}
public enum SortDirection
{
ASC, DESC
}