2009-02-12 26 views
82

He oído que "todos" usan consultas SQL parametrizadas para protegerse contra ataques de inyección SQL sin tener que actualizar cada parte de la entrada del usuario.¿Cómo creo una consulta SQL parametrizada? ¿Por qué debería?

¿Cómo se hace esto? ¿Lo obtiene automáticamente cuando usa procedimientos almacenados?

Así que mi entender esto es no parametrizada:

cmdText = String.Format("SELECT foo FROM bar WHERE baz = '{0}'", fuz) 

sería esto parametrizar?

cmdText = String.Format("EXEC foo_from_baz '{0}'", fuz) 

¿O tengo que hacer algo más extenso como este para protegerme de la inyección de SQL?

With command 
    .Parameters.Count = 1 
    .Parameters.Item(0).ParameterName = "@baz" 
    .Parameters.Item(0).Value = fuz 
End With 

¿Existen otras ventajas en el uso de consultas parametrizadas además de las consideraciones de seguridad?

Actualización: este gran artículo fue vinculado en una de las referencias de preguntas de Grotok. http://www.sommarskog.se/dynamic_sql.html

+0

Me pareció chocante que aparentemente esta pregunta no se haya formulado antes en Stackoverflow. ¡Muy buena! –

+3

Oh, tiene. En términos muy diferentes, por supuesto, pero lo ha hecho. –

+0

No use el bloque "Con". Nunca. "Con" es una de las razones por las cuales muchas personas tienen una fuerte aversión por VB. – yfeldblum

Respuesta

67

Su ejemplo Exec no se ha parametrizado. Es necesario consultas con parámetros (declaraciones preparadas en algunos círculos) para prevenir la entrada como esto cause daños:

'; DROP TABLE bar; -

que trate de poner en su variable de fuz (o Don 't, si valoras tu tabla de barras). También son posibles consultas más sutiles y perjudiciales.

Aquí hay un ejemplo de cómo se hace con los parámetros de 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 

Los procedimientos almacenados a veces se atribuye la prevención de la inyección de SQL. Sin embargo, la mayoría de las veces todavía tiene que llamarlos usando parámetros de consulta o no ayudan. Si usa los procedimientos almacenados exclusivamente, puede desactivar los permisos de SELECT, UPDATE, ALTER, CREATE, DELETE, etc (casi todo excepto EXEC) para la cuenta de usuario de la aplicación y obtener cierta protección de esa manera.

+0

¿Puede explicar mejor este 'cmd.Parameters.Add (" @ Baz ", SqlDbType.VarChar, 50) .Value = Baz' por favor? –

+1

@CaryBondoc, ¿qué quieres saber? Esa línea crea un parámetro llamado '@ Baz' que es de tipo' varchar (50) 'al que se le asigna el valor de la cadena' Baz'. –

+0

también podría decir "command.parameters.addiwthvalue (" @ Baz ", 50)" –

5

Quiere ir con su último ejemplo, ya que es el único realmente parametrizado. Además de los problemas de seguridad (que son mucho más comunes, entonces podría pensar) es mejor dejar ADO.NET manejar la parametrización ya que no puede estar seguro si el valor que está pasando requiere comillas simples o no sin inspeccionar el Type de cada parámetro.

[Editar] A continuación se muestra un ejemplo:

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); 
+3

Teniendo en cuenta esto: .Net cadenas son unicode, por lo que el parámetro asumirá NVarChar por defecto.Si se trata realmente de una columna VarChar, esto puede causar grandes problemas de rendimiento. –

1

Su texto del comando que ser como:

cmdText = "SELECT foo FROM bar WHERE baz = ?" 

cmdText = "EXEC foo_from_baz ?" 

A continuación, agregue los valores de los parámetros.De esta manera se garantiza que el valor con sólo terminan siendo utilizado como un valor, mientras que con el otro método si fuz variable se establece en

"x'; delete from foo where 'a' = 'a" 

se puede ver lo que podría suceder?

2

La mayoría de las personas haría esto a través de una biblioteca de lenguaje de programación del lado del servidor, como PHP PDO o Perl DBI.

Por ejemplo, en 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*/} 

Este se encarga de escapar de sus datos para la inserción de base de datos.

Una ventaja es que puede repetir una inserción muchas veces con una declaración preparada, ganando una ventaja de velocidad.

Por ejemplo, en la consulta anterior pude preparar la declaración una vez, y luego recorrer la creación de la matriz de datos a partir de un conjunto de datos y repetir el -> ejecutar tantas veces como sea necesario.

14

Definitivamente el segundo.

consultas parametrizadas tienen dos ventajas principales:

  • de seguridad: Es una buena manera de evitar SQL Injection vulnerabilidades
  • Rendimiento: Si se invoca regularmente la misma consulta sólo con los diferentes parámetros de una consulta parametrizada podría permitir que el base de datos para almacenar en caché sus consultas, que es una fuente considerable de ganancia de rendimiento.
  • Extra: No tendrá que preocuparse por los problemas de formato de fecha y hora en el código de su base de datos. De forma similar, si su código se ejecutará alguna vez en máquinas con una configuración regional que no esté en inglés, no tendrá problemas con los puntos decimales/comas decimales.
+0

Espero que esta publicación se haya escrito cuando "la segunda" era otra cosa. Tal como está actualmente, ¡esta respuesta está completamente equivocada! –

Cuestiones relacionadas