Я слышал, что "каждый" использует параметризованные 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
Существуют ли другие преимущества использования параметризованных запросов помимо соображений безопасности?
Обновление: эта замечательная статья была связана в одном из вопросов, заданных Гротоком. http://www.sommarskog.se/dynamic_sql.html
Ваш EXEC-пример не будет параметризован. Вам нужны параметризованные запросы (подготовленные операторы в некоторых кругах), чтобы предотвратить появление такого рода:
'; панель DROP TABLE; -
Попробуйте поместить это в свою переменную 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
.
Определенно последний, т.е.
Или мне нужно сделать что-то более обширное...? (Да,
cmd.Parameters.Add()
)
Параметризированные запросы имеют два основных преимущества:
Вы хотите перейти со своим последним примером, поскольку это единственный, который действительно параметризован. Помимо проблем безопасности (которые гораздо более распространены, чем вы могли бы подумать), лучше всего разрешить ADO.NET обрабатывать параметризацию, поскольку вы не можете быть уверены, что значение, которое вы передаете, требует одинарных кавычек вокруг него или нет, не проверяя Type
каждого параметра.
[Изменить] Вот пример:
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);
Большинство людей сделают это через библиотеку языков программирования на стороне сервера, такую как PHP PDO или 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/Express
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