Предотвращает ли этот код SQL-инъекцию?

Фон

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

Вопрос

Какой параметр "Key" может разорвать функцию PrepareString и позволить мне выполнить оператор DROP?

Фрагмент кода

Public Shared Function GetRecord(ByVal Key As String) As Record
    Dim Sql As New StringBuilder()

    With Sql
        .Append("SELECT * FROM TableName")
        If String.IsNullOrEmpty(Agency) Then
            .Append(" ORDER BY DateAdded")
        Else
            .Append(" WHERE Key = '")
            .Append(PrepareString(Key))
            .Append("'")
        End If
    End With

    Return ExecuteQuery(Sql.ToString())
End Function

Public Shared Function PrepareString(ByVal Value As String) As String
    Return Value.Replace("''", "'") _
                .Replace("'", "''") _
                .Replace("`", "''") _
                .Replace("´", "''") _
                .Replace("--", "")
End Function

Ответ 1

В ответ на ваш прямой вопрос: предотвращает ли этот код SQL-инъекцию: No

Здесь доказательство - нажмите эту строку через метод PrepareString:

Dim input = "'" & Chr(8) & "; Drop Table TableName; - " & Chr(8) & "-"
Dim output = PrepareString(input)

Console.WriteLine(input)
Console.WriteLine(output)

Я изменил метод GetRecord, который вы опубликовали, чтобы вернуть полностью подготовленную строку SQL, а не получить запись из базы данных:

Console.WriteLine(GetRecord(output))

И это вывод

Input  = ; Drop Table TableName; --
Output = '; Drop Table TableName; --
Query  = SELECT * FROM TableName WHERE Key = ''; Drop Table TableName; --'

Добавьте 1 дополнительную строку кода:

My.Computer.Clipboard.SetText(input)

И у вас есть строка, которую вам нужно скопировать прямо в буфер обмена, чтобы вставить в поле ввода на веб-сайте, чтобы завершить SQL-инъекцию:

'; Drop Table TableName; - -

[Отмечая, что управляющие символы были опущены из пост-вывода StackOverflow, поэтому вам нужно будет следовать примеру кода для создания вашего вывода]

После запуска метода PrepareString он будет иметь тот же самый результат - код ASCII Chr (8) - это обратное пространство, которое удалит лишние "", которые вы добавляете к моему, который закроет вашу строку, а затем Я могу добавить все, что захочу, в конце. Ваша PrepareString не видит моего - потому что я фактически использую - с символом обратного пробела, чтобы удалить пробел.

Результирующий SQL-код, который вы создаете, будет выполнять оператор Drop Table без пробелов и незамедлительно игнорирует остальную часть вашего запроса.

Самое интересное в том, что вы можете использовать непечатаемые символы, чтобы в принципе обойти любую проверку персонажа, которую вы можете придумать. Поэтому безопаснее использовать параметризованные запросы (это не то, что вы просили, но лучший путь, чтобы избежать этого).

Ответ 2

Чтобы ответить на ваш спорный вопрос, он не будет работать.

.Replace("``", "''") предотвратит законные запросы с помощью ``

.Replace("´", "''") предотвратит законные запросы с помощью '' '

.Replace("--", "") будет препятствовать законным запросам с '-' в них

.Replace("''", "'") будет неправильно изменять законные запросы с помощью '' '' в них

и т.д.

Кроме того, полный набор escape-символов может варьироваться от одной РСУБД к другой. Параметрированные запросы FTW.

Ответ 3

Я думаю, что это невозможно, если вы просто замените "на". Я слышал, что можно изменить символ escape-кавычки, который может потенциально нарушить это, однако я не уверен. Я думаю, что вы в безопасности.

Ответ 4

Я думаю, что это безопасно (по крайней мере, на SQL-сервере), и я также думаю, что единственное, что вам действительно нужно сделать, это s = s.Replace("'", "''"). Конечно, вы должны использовать параметризованные запросы, но вы уже знаете это.

Ответ 5

Эта статья статья MSDN охватывает большинство вещей, которые вам нужно искать (я боюсь сказать все, когда дело доходит до SQL инъекции).

Но я повторю все остальные параметры параметров параметров параметров.

Что касается вашего примера, некоторые gotchas [Edit: Update these]:

  • не будет содержать строку "1 ИЛИ 1 = 1", чтобы пользователь мог вернуть все

  • или хуже "1; drop table sometablename"

В соответствии со статьей, которую вы хотите проверить:

; - Разделитель запросов.

'- разделитель строки символов.

- - Разделитель комментариев.

/*.../- Комментировать разделители. Текст между/и */не оценивается сервера.

xp_ - Используется в начале имени расширенные в каталоге хранимые процедуры, таких как xp_cmdshell.

Ответ 6

Вы пытаетесь черным символам списка реализовать свою собственную версию SQL Escaping. Я бы предложил рассмотреть этот URL - SQL-экранирование не обязательно является наихудшим вариантом (то есть быстро фиксирует существующие приложения), но это нужно сделать прямо избегайте уязвимостей.

Этот URL-адрес ссылается на другую страницу для экранирования в SQL Server, где автор дает советы, которые помогут вам избежать уязвимостей без ограничения функциональности.

Если это помогает, в статьях также предлагается избегать фигурных скобок (я называю их квадратными скобками, но []).

Ответ 7

Если вы попытаетесь использовать свой код, кто-то может передать ключ (; select * from table; и получить список того, что когда-либо нужно.)

В вашем коде вы не будете проверять наличие двоеточия, которое позволяет вам завершить утверждение t-sql и запустить другой.

Я бы пошел с параметризованным запросом.