Słyszałem, że „wszyscy” używają sparametryzowanych zapytań SQL do ochrony przed atakami typu SQL injection bez konieczności sprawdzania każdego elementu wprowadzanego przez użytkownika.
Jak Ty to robisz? Czy otrzymujesz to automatycznie podczas korzystania z procedur składowanych?
W moim rozumieniu to nie jest sparametryzowane:
cmdText = String.Format("SELECT foo FROM bar WHERE baz = '{0}'", fuz)
Czy byłoby to sparametryzowane?
cmdText = String.Format("EXEC foo_from_baz '{0}'", fuz)
A może muszę zrobić coś bardziej rozbudowanego, aby uchronić się przed wstrzyknięciem SQL?
With command
.Parameters.Count = 1
.Parameters.Item(0).ParameterName = "@baz"
.Parameters.Item(0).Value = fuz
End With
Czy poza względami bezpieczeństwa istnieją inne zalety korzystania z zapytań parametrycznych?
Aktualizacja: ten wspaniały artykuł został powiązany w jednym z pytań dotyczących odniesienia przez Grotok. http://www.sommarskog.se/dynamic_sql.html
sql
vb.net
sql-parametrized-query
Jim się liczy
źródło
źródło
Odpowiedzi:
Twój przykład EXEC NIE byłby sparametryzowany. Potrzebujesz sparametryzowanych zapytań (przygotowanych instrukcji w niektórych kręgach), aby zapobiec uszkodzeniom takich danych wejściowych:
Spróbuj umieścić to w zmiennej fuz (lub nie, jeśli cenisz swój stół słupkowy). Możliwe są również bardziej subtelne i szkodliwe zapytania.
Oto przykład sposobu wykonywania parametrów z serwerem Sql:
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
Procedurom składowanym czasami przypisuje się zapobieganie wstrzykiwaniu kodu SQL. Jednak w większości przypadków nadal musisz wywoływać je za pomocą parametrów zapytania lub nie pomagają. Jeśli używasz wyłącznie procedur składowanych , możesz wyłączyć uprawnienia SELECT, UPDATE, ALTER, CREATE, DELETE itp. (Prawie wszystko oprócz EXEC) dla konta użytkownika aplikacji i uzyskać w ten sposób pewną ochronę.
źródło
cmd.Parameters.Add("@Baz", SqlDbType.VarChar, 50).Value = Baz
?@Baz
który jest typuvarchar(50)
, któremu przypisano wartośćBaz
ciągu.AddWithValue("@Baz", Baz)
, możesz to zrobić, ale nie powinieneś , zwłaszcza że konwersja wartości ciągów, które są domyślnie mapowanenvarchar
na rzeczywistyvarchar
typ, jest jednym z najczęstszych miejsc, które mogą wywoływać efekty wymienione w tym łączu.Zdecydowanie ostatni, tj
Zapytania parametryzowane mają dwie główne zalety:
źródło
Chcesz przejść do ostatniego przykładu, ponieważ jest to jedyny prawdziwie sparametryzowany. Oprócz obaw związanych z bezpieczeństwem (które są znacznie bardziej rozpowszechnione niż mogłoby się wydawać) najlepiej pozwolić ADO.NET zająć się parametryzacją, ponieważ nie możesz być pewien, czy wartość, którą przekazujesz, wymaga pojedynczych cudzysłowów, czy nie bez sprawdzenia
Type
każdego parametru .[Edytuj] Oto przykład:
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);
źródło
Większość ludzi zrobiłaby to za pomocą biblioteki języka programowania po stronie serwera, takiej jak PDO PHP lub Perl DBI.
Na przykład w przypadku ChNP:
$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*/}
Dba to o ucieczkę danych do wstawienia do bazy danych.
Zaletą jest to, że możesz wielokrotnie powtarzać wstawkę z jednym przygotowanym stwierdzeniem, uzyskując przewagę szybkości.
Na przykład w powyższym zapytaniu mogłem raz przygotować instrukcję, a następnie utworzyć pętlę nad tworzeniem tablicy danych z zestawu danych i powtórzyć -> wykonać tyle razy, ile potrzeba.
źródło
Twój tekst polecenia musi wyglądać następująco:
cmdText = "SELECT foo FROM bar WHERE baz = ?" cmdText = "EXEC foo_from_baz ?"
Następnie dodaj wartości parametrów. W ten sposób zapewnia, że wartość zostanie użyta tylko jako wartość, podczas gdy w przypadku drugiej metody, jeśli zmienna fuz jest ustawiona na
"x'; delete from foo where 'a' = 'a"
czy widzisz, co może się stać?
źródło
Oto krótka klasa, na której można zacząć od języka SQL. Możesz z niej budować i dodawać do klasy.
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
źródło