Я слышал, что «все» используют параметризованные SQL-запросы для защиты от атак SQL-инъекций, не проверяя каждый элемент пользовательского ввода.
Как ты делаешь это? Получаете ли вы это автоматически при использовании хранимых процедур?
Итак, я понимаю, что это не параметризовано:
cmdText = String.Format("SELECT foo FROM bar WHERE baz = '{0}'", fuz)
Будет ли это параметризовано?
cmdText = String.Format("EXEC foo_from_baz '{0}'", fuz)
Или мне нужно сделать что-то более обширное, чтобы защитить себя от SQL-инъекции?
With command
.Parameters.Count = 1
.Parameters.Item(0).ParameterName = "@baz"
.Parameters.Item(0).Value = fuz
End With
Есть ли другие преимущества использования параметризованных запросов помимо соображений безопасности?
Обновление: эта замечательная статья была связана с одним из вопросов, на которые ссылается Grotok. http://www.sommarskog.se/dynamic_sql.html
sql
vb.net
sql-parametrized-query
Джим Графс
источник
источник
Ответы:
Ваш пример EXEC НЕ будет параметризован. Вам нужны параметризованные запросы (подготовленные операторы в некоторых кругах), чтобы предотвратить повреждение такого ввода:
Попробуйте поместить это в свою переменную fuz (или не делайте этого, если вы цените свою столбчатую таблицу). Возможны и более тонкие и опасные вопросы.
Вот пример того, как вы настраиваете параметры с помощью Sql Server:
Public Function GetBarFooByBaz(ByVal Baz As String) As String Dim sql As String = "SELECT foo FROM bar WHERE baz= @Baz" Using cn As New SqlConnection("Your connection string here"), _ cmd As New SqlCommand(sql, cn) cmd.Parameters.Add("@Baz", SqlDbType.VarChar, 50).Value = Baz Return cmd.ExecuteScalar().ToString() End Using End Function
Иногда считают, что хранимые процедуры предотвращают внедрение SQL. Однако в большинстве случаев вам все равно придется вызывать их с использованием параметров запроса, иначе они не помогут. Если вы используете исключительно хранимые процедуры , вы можете отключить разрешения для SELECT, UPDATE, ALTER, CREATE, DELETE и т.д. (почти все, кроме EXEC) для учетной записи пользователя приложения и таким образом получить некоторую защиту.
источник
cmd.Parameters.Add("@Baz", SqlDbType.VarChar, 50).Value = Baz
?@Baz
типа,varchar(50)
которому присвоено значениеBaz
строки.AddWithValue("@Baz", Baz)
, вы можете это сделать, но не должны , особенно потому, что преобразование строковых значений, которые по умолчанию сопоставляются сnvarchar
фактическимvarchar
типом, является одним из наиболее распространенных мест, которые могут вызвать эффекты, упомянутые в этой ссылке.Однозначно последний, т.е.
У параметризованных запросов есть два основных преимущества:
источник
Вы хотите продолжить свой последний пример, так как это единственный действительно параметризованный. Помимо проблем безопасности (которые гораздо более распространены, чем вы можете подумать), лучше всего позволить ADO.NET обрабатывать параметризацию, поскольку вы не можете быть уверены, требует ли передаваемое вами значение одинарные кавычки или нет, не проверив
Type
каждый параметр. .[Edit] Вот пример:
SqlCommand command = new SqlCommand( "select foo from bar where baz = @baz", yourSqlConnection ); SqlParameter parameter = new SqlParameter(); parameter.ParameterName = "@baz"; parameter.Value = "xyz"; command.Parameters.Add(parameter);
источник
Большинство людей будет делать это через библиотеку языков программирования на стороне сервера, такую как PDO PHP или Perl DBI.
Например, в PDO:
$dbh=pdo_connect(); //you need a connection function, returns a pdo db connection $sql='insert into squip values(null,?,?)'; $statement=$dbh->prepare($sql); $data=array('my user supplied data','more stuff'); $statement->execute($data); if($statement->rowCount()==1){/*it worked*/}
Это позаботится об экранировании ваших данных для вставки в базу данных.
Одним из преимуществ является то, что вы можете повторять вставку много раз с одним подготовленным оператором, что дает преимущество в скорости.
Например, в приведенном выше запросе я мог бы подготовить оператор один раз, а затем в цикле создать массив данных из набора данных и повторить -> выполнить столько раз, сколько необходимо.
источник
Текст вашей команды должен быть таким:
cmdText = "SELECT foo FROM bar WHERE baz = ?" cmdText = "EXEC foo_from_baz ?"
Затем добавьте значения параметров. Этот способ гарантирует, что значение con будет использоваться только как значение, тогда как с другим методом, если для переменной fuz установлено значение
"x'; delete from foo where 'a' = 'a"
ты видишь, что может случиться?
источник
Вот небольшой класс, который нужно начать с SQL, и вы можете создать его и добавить в класс.
MySQL
Public Class mysql 'Connection string for mysql Public SQLSource As String = "Server=123.456.789.123;userid=someuser;password=somesecurepassword;database=somedefaultdatabase;" 'database connection classes Private DBcon As New MySqlConnection Private SQLcmd As MySqlCommand Public DBDA As New MySqlDataAdapter Public DBDT As New DataTable Public BindSource As New BindingSource ' parameters Public Params As New List(Of MySqlParameter) ' some stats Public RecordCount As Integer Public Exception As String Function ExecScalar(SQLQuery As String) As Long Dim theID As Long DBcon.ConnectionString = SQLSource Try DBcon.Open() SQLcmd = New MySqlCommand(SQLQuery, DBcon) 'loads params into the query Params.ForEach(Sub(p) SQLcmd.Parameters.AddWithValue(p.ParameterName, p.Value)) 'or like this is also good 'For Each p As MySqlParameter In Params ' SQLcmd.Parameters.AddWithValue(p.ParameterName, p.Value) ' Next ' clears params Params.Clear() 'return the Id of the last insert or result of other query theID = Convert.ToInt32(SQLcmd.ExecuteScalar()) DBcon.Close() Catch ex As MySqlException Exception = ex.Message theID = -1 Finally DBcon.Dispose() End Try ExecScalar = theID End Function Sub ExecQuery(SQLQuery As String) DBcon.ConnectionString = SQLSource Try DBcon.Open() SQLcmd = New MySqlCommand(SQLQuery, DBcon) 'loads params into the query Params.ForEach(Sub(p) SQLcmd.Parameters.AddWithValue(p.ParameterName, p.Value)) 'or like this is also good 'For Each p As MySqlParameter In Params ' SQLcmd.Parameters.AddWithValue(p.ParameterName, p.Value) ' Next ' clears params Params.Clear() DBDA.SelectCommand = SQLcmd DBDA.Update(DBDT) DBDA.Fill(DBDT) BindSource.DataSource = DBDT ' DBDT will contain your database table with your records DBcon.Close() Catch ex As MySqlException Exception = ex.Message Finally DBcon.Dispose() End Try End Sub ' add parameters to the list Public Sub AddParam(Name As String, Value As Object) Dim NewParam As New MySqlParameter(Name, Value) Params.Add(NewParam) End Sub End Class
MS SQL / Экспресс
Public Class MSSQLDB ' CREATE YOUR DB CONNECTION 'Change the datasource Public SQLSource As String = "Data Source=someserver\sqlexpress;Integrated Security=True" Private DBCon As New SqlConnection(SQLSource) ' PREPARE DB COMMAND Private DBCmd As SqlCommand ' DB DATA Public DBDA As SqlDataAdapter Public DBDT As DataTable ' QUERY PARAMETERS Public Params As New List(Of SqlParameter) ' QUERY STATISTICS Public RecordCount As Integer Public Exception As String Public Sub ExecQuery(Query As String, Optional ByVal RunScalar As Boolean = False, Optional ByRef NewID As Long = -1) ' RESET QUERY STATS RecordCount = 0 Exception = "" Dim RunScalar As Boolean = False Try ' OPEN A CONNECTION DBCon.Open() ' CREATE DB COMMAND DBCmd = New SqlCommand(Query, DBCon) ' LOAD PARAMS INTO DB COMMAND Params.ForEach(Sub(p) DBCmd.Parameters.Add(p)) ' CLEAR PARAMS LIST Params.Clear() ' EXECUTE COMMAND & FILL DATATABLE If RunScalar = True Then NewID = DBCmd.ExecuteScalar() End If DBDT = New DataTable DBDA = New SqlDataAdapter(DBCmd) RecordCount = DBDA.Fill(DBDT) Catch ex As Exception Exception = ex.Message End Try ' CLOSE YOUR CONNECTION If DBCon.State = ConnectionState.Open Then DBCon.Close() End Sub ' INCLUDE QUERY & COMMAND PARAMETERS Public Sub AddParam(Name As String, Value As Object) Dim NewParam As New SqlParameter(Name, Value) Params.Add(NewParam) End Sub End Class
источник