Запретить 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
}