J'ai entendu dire que "tout le monde" utilise des requêtes SQL paramétrées pour se protéger contre les attaques par injection SQL sans devoir valider toutes les entrées d'utilisateur.
Comment est-ce que tu fais ça? Obtenez-vous cela automatiquement lorsque vous utilisez des procédures stockées?
Donc, si j'ai bien compris, ceci n'est pas paramétré:
cmdText = String.Format("SELECT foo FROM bar WHERE baz = '{0}'", fuz)
Cela serait-il paramétré?
cmdText = String.Format("EXEC foo_from_baz '{0}'", fuz)
Ou dois-je faire quelque chose de plus complet comme celui-ci pour me protéger de l'injection SQL?
With command
.Parameters.Count = 1
.Parameters.Item(0).ParameterName = "@baz"
.Parameters.Item(0).Value = fuz
End With
Y a-t-il d'autres avantages à utiliser des requêtes paramétrées en plus des considérations de sécurité?
Mise à jour: Cet excellent article a été lié à l’une des références de questions de Grotok . http://www.sommarskog.se/dynamic_sql.html
Votre exemple EXEC ne serait PAS paramétré. Vous avez besoin de requêtes paramétrées (instructions préparées dans certains cercles) pour empêcher des entrées de ce type de causer des dommages:
'; DROP TABLE bar; -
Essayez de mettre cela dans votre variable fuz (ou pas, si vous valorisez votre barre). Des requêtes plus subtiles et dommageables sont également possibles.
Voici un exemple de la manière dont vous définissez les paramètres avec 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
On empêche parfois les procédures stockées d'empêcher l'injection SQL. Cependant, la plupart du temps, vous devez toujours les appeler à l'aide de paramètres de requête ou ils ne vous aident pas. Si vous utilisez des procédures stockées exclusivement , vous pouvez désactiver les autorisations pour les comptes SELECT, UPDATE, ALTER, CREATE, DELETE, etc.
Certainement le dernier, c'est-à-dire.
Ou dois-je faire quelque chose de plus étendu ...? (Oui,
cmd.Parameters.Add()
)
Les requêtes paramétrées présentent deux avantages principaux:
Vous voulez aller avec votre dernier exemple car c'est le seul qui soit vraiment paramétré. Outre les problèmes de sécurité (qui sont beaucoup plus répandus qu’on pourrait le penser), il est préférable de laisser ADO.NET gérer le paramétrage, car vous ne pouvez pas savoir avec certitude si la valeur que vous transmettez requiert des guillemets simples ou non, sans inspection préalable de la variable Type
de chaque élément. paramètre.
[Modifier] Voici un exemple:
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);
La plupart des gens le feraient via une bibliothèque de langage de programmation côté serveur, telle que PDO de PHP ou Perl DBI.
Par exemple, dans 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*/}
Cela évite que vos données ne soient insérées dans la base de données.
Un des avantages est que vous pouvez répéter une insertion plusieurs fois avec une seule instruction préparée, ce qui vous procure un avantage en termes de rapidité.
Par exemple, dans la requête ci-dessus, je pourrais préparer l’instruction une fois, puis créer un tableau de données à partir d’un tas de données et répéter le -> exécuter autant de fois que nécessaire.
Votre texte de commande doit ressembler à:
cmdText = "SELECT foo FROM bar WHERE baz = ?"
cmdText = "EXEC foo_from_baz ?"
Ajoutez ensuite des valeurs de paramètre. De cette façon, on s’assure que la valeur ne sera utilisée qu’en tant que valeur, alors que l’autre méthode si la variable fuz est définie
"x'; delete from foo where 'a' = 'a"
pouvez-vous voir ce qui pourrait arriver?
Voici une courte classe pour commencer avec SQL et vous pouvez construire à partir de là et ajouter à la classe.
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