Защита SQL от инъекций

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

Public Shared Function SaveNewPerson(ByVal firstName As String, lastName As String, ByVal age As Integer, ByVal postcode As String, m_cn As OleDbConnection)

    Dim tr As OleDbTransaction = Nothing

    Try
        tr = m_cn.BeginTransaction()

        Dim Dc As New OleDbCommand
        Dc.Connection = m_cn

        Dc.CommandText = "INSERT INTO tblPerson([firstName], [lastName], [age], [postcode]) VALUES('" & firstName & "', '" & lastName & "', '" & age & "', '" & postcode & "')"
        Dc.Transaction = tr
        Dc.ExecuteNonQuery()

        Dim personID As Integer

        Dc.CommandText = "SELECT SCOPE_IDENTITY() AS personID"
        Dc.CommandType = CommandType.Text
        personID = CType(Dc.ExecuteScalar(), Integer)

        tr.Commit()

    Catch ex As Exception

        tr.Rollback()

        Throw
    End Try

End Function

person Community    schedule 19.07.2016    source источник
comment
Возможный дубликат Передача параметра для запроса базы данных Access   -  person Matt Wilko    schedule 19.07.2016
comment
@MattWilko Привет, Мэтт, я использую SQLServer, а не базу данных Access, наверное, мне следовало уточнить это в вопросе, но именно поэтому я сказал, что OleDb был странным выбором.   -  person    schedule 19.07.2016
comment
Пожалуйста, опубликуйте схему/определение таблицы. также, какой сервер БД вы используете?   -  person fcm    schedule 19.07.2016
comment
@fcm определения нет, я создал его в SQLServer перед началом проекта vb   -  person    schedule 19.07.2016
comment
Я считаю, что Access использует OLEDB, поэтому размещенное там решение будет работать для вас.   -  person Matt Wilko    schedule 19.07.2016
comment
@MattWilko Хорошо, я попробую, спасибо, но в этом примере SQL дает значения для вставки (константы), но это не сработает для значений, которые неизвестны и меняются каждый раз, верно?   -  person    schedule 19.07.2016
comment
Просто замените строковые константы своими переменными   -  person Matt Wilko    schedule 19.07.2016
comment
Если вы используете Sql Server, вам не следует использовать OleDb. Вы должны использовать классы в System.Data.SqlClient. Они оптимизированы специально для Sql Server.   -  person Chris Dunaway    schedule 20.07.2016


Ответы (2)


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

    dc.commandText = "Your stored procedure name"
    dc.commandType = CommandType.StoredProcedure
    Dim myParam as oledb.OleDbParameter = dc.parameters.add("@personID", oledbtype.int)
    myParam.Direction = ParameterDirection.ReturnValue
    dc.Parameters.Add("@firstName", OleDbType.VarChar).Value = [firstname]
    ....
    ....

    Dim returnId as Integer = Cint(dc.Parameters("@personID").Value)   
person Leprechaun    schedule 19.07.2016
comment
Но мне нужно, чтобы оператор SQL вставлял данные в базу данных, а затем после этого создавал идентификатор для каждой записи, а не сохранял его, а затем в отдельной функции возвращал идентификатор. Я думаю, что ответ ниже, вероятно, лучше, так как он работает, если не считать одной ошибки, которую я получаю. - person ; 19.07.2016
comment
@joe Это даст вам идентификатор после вставки записи. Вы делаете это в хранимой процедуре DECLARE '@Id' AS INT SET '@Id' = SCOPE_IDENTITY() RETURN '@Id.' - person Leprechaun; 19.07.2016

   Dc.CommandText = "INSERT INTO tblPerson([firstName], [lastName], [age], [postcode]) VALUES('" & firstName & "', '" & lastName & "', '" & age & "', '" & postcode & "')"

Измените это на

Dc.CommandText = "INSERT INTO tblPerson([firstName], [lastName], [age], [postcode]) VALUES(?, ?, ?, ?)"
Dc.Parameters.Add("@first", OleDbType.VarChar, firstName)
Dc.Parameters.Add("@last", OleDbType.VarChar, lastName)
Dc.Parameters.Add("@age", OleDbType.Integer, age)
Dc.Parameters.Add("@postcode", OleDbType.VarChar, postcode )

(Проверьте, правильно ли передано значение OldDbType.)

NB. порядок в наборе параметров определяет, какой параметр соответствует какому ? заполнителю. Имена, данные параметрам, (кажется) игнорируются.

person Richard    schedule 19.07.2016
comment
Я считаю, что вы должны использовать заполнитель ? для параметров запроса OLEDB? - person Matt Wilko; 19.07.2016
comment
@MattWilko Использование этого кода напрямую скопировано и вставлено из ответа Ричардса. Данные, которые я ввожу: firstName как Test, lastName как User, age как 30 и почтовый индекс как ABC 123 В настоящее время я получаю сообщение об ошибке в строке Dc.Parameters.Add("@first", OleDbType.VarChar, firstName), говорящее Conversion from string "Test" to type 'Integer' is not valid. Является ли это причиной этого, необходимо использовать вопрос Метки? - person ; 19.07.2016
comment
@joe Возможно, вы правы, обновлено, чтобы использовать правильный заполнитель параметра. - person Richard; 19.07.2016
comment
@Richard Привет, извините, это все еще не сработало :( Я создал новый вопрос, в котором у меня есть рабочее утверждение, но с одной ошибкой в ​​​​конце, если вы можете помочь с этим? stackoverflow.com/questions/38457341/ - person ; 19.07.2016
comment
@Joe: на этот новый вопрос уже дан ответ. Возможно, вам нужен только один вопрос, но убедитесь, что это полный код (например, в этом вопросе нет тестового значения для преобразования). - person Richard; 19.07.2016
comment
@Richard Все значения передаются из текстовых полей в форме. Во время отладки все параметры передаются правильно, поскольку они возвращают значения, которые я ввел в соответствующие текстовые поля. - person ; 19.07.2016
comment
@joe Вам нужно выполнить преобразование типа в правильный тип (БД может, но становится сложнее обрабатывать ошибки, например, когда для возраста отправляется нечисловое значение). - person Richard; 19.07.2016
comment
@Richard Это невозможно, каждое текстовое поле поля проверяется на прием только определенных символов (например, возраст может принимать только числа, имена - только буквы, дефис и т. д.) - person ; 19.07.2016