.NET Framework proporciona un gran número de clases y servicios muy útiles, que permiten a los programadores escribir aplicaciones seguras (vea Proteger aplicaciones). En la sección Información general sobre codificación segura se proporciona información general sobre las diversas formas de diseñar código para que funcione con el sistema de seguridad .NET Framework. También se incluye un vínculo a Instrucciones de codificación segura, que a su vez contiene vínculos a temas de seguridad adicionales. Además, debe seguir las prácticas de codificación de acceso de datos seguro en el código de ADO.NET para evitar ataques de posibles agresores. Generalmente, los ataques relacionados con ADO.NET provienen de agresores que utilizan inyecciones de SQL o que obtienen información de base de datos privada a partir de las excepciones devueltas por una aplicación. Estos ataques se pueden neutralizar mediante el uso de comandos con parámetros y un control de excepciones eficaz.
Prevenir ataques de inyecciones de SQL
Las inyecciones de SQL se producen cuando un agresor inserta o inyecta instrucciones SQL adicionales en comandos procesados en un origen de datos o en un servidor de base de datos. Estos comandos pueden recuperar información confidencial, además de modificar o destruir la información del servidor de base de datos. Si las instrucciones SQL insertadas son sintácticamente correctas, es imposible detectar la manipulación en el servidor mediante programación. Por consiguiente, debe asegurarse de que los datos introducidos por el usuario no se pueden insertar en los comandos ejecutados. Estas directrices le ayudarán a protegerse contra los ataques de inyecciones de SQL:
-
Utilice siempre una cuenta de privilegios de nivel más bajo.
-
Valide siempre todos los datos introducidos por el usuario desde orígenes externos.
-
Pase siempre valores de columnas como parámetros, en lugar de valores concatenados.
Ejemplo de ataque de inyección de SQL
El siguiente código es vulnerable a un ataque de inyección de SQL porque acepta cualquier dato introducido por el usuario de un control TextBox, lo concatena con una instrucción Transact-SQL y envía la cadena concatenada a SQL Server para su procesamiento. Si la instrucción Transact-SQL concatenada es sintácticamente correcta y el usuario que realiza la llamada cuenta con los permisos adecuados, SQL Server procesará los comandos. Al utilizar la concatenación de cadenas se abre la puerta al posible ataque de la aplicación por parte de un agresor que introduzca datos que puedan ejecutar comandos imprevistos en el servidor.
' Retrieve CustomerID to search for.
Dim ID As String = TextBox1.Text
' The following line of code allows for SQL injection attack.
Dim query As String = _
"SELECT * FROM dbo.Orders WHERE CustomerID = '" & ID & "';"
' Code connecting to a data source has been omitted for brevity.
Dim cmd As SqlCommand = New SqlCommand(query, connection)
Dim reader As SqlDataReader = cmd.ExecuteReader()
reader.Close()
// Retrieve CustomerID to search for.
string ID =TextBox1.Text;
// The following line of code allows for SQL injection attack.
string query =
"SELECT * FROM dbo.Orders WHERE CustomerID = '" + ID + "';"
// Code connecting to a data source has been omitted for brevity.
SqlCommand cmd = new SqlCommand(query, connection);
SqlDataReader reader = cmd.ExecuteReader();
reader.Close();
En este caso, un posible agresor podría utilizar el valor "ABCD';DELETE FROM Orders;--" para el CustomerID, donde ABCD sería un valor válido para la cláusula WHERE prevista. La comilla simple después de ABCD completa la cláusula WHERE para la consulta deseada y el punto y coma delimita el final del primer comando. La instrucción DELETE FROM inicia un nuevo comando que representa el ataque de inyección de SQL. La secuencia de dos guiones (--) indica a SQL Server que lo que sigue es un comentario que se debe ignorar, de manera que la comilla simple de cierre y el punto y coma concatenados en el código original (+ "';") no generan errores de sintaxis. En este caso, el servidor procesaría la siguiente cadena, formada por dos comandos separados:
SELECT * FROM dbo.Orders WHERE CustomerID = 'ABCD';DELETE FROM Orders;--'
Cuando SQL Server procesa el primer comando, selecciona los registros coincidentes en la tabla Orders. Al procesar el segundo comando, elimina todos los registros de la tabla Orders.
Los ataques de inyecciones de SQL pueden contener sintaxis para eliminar tablas o para ejecutar otros comandos en el servidor. El alcance de los daños depende de los permisos concedidos al proceso de llamada. Para el uso de concatenación de cadenas es necesario que se hayan concedido los permisos para ejecutar SELECT en las tablas, de manera que los datos se encuentran expuestos al agresor.
Utilizar comandos con parámetros
Los parámetros proporcionan un método práctico para organizar los valores que se pasan con una instrucción Transact-SQL o los valores que se pasan a un procedimiento almacenado. Además, los parámetros pueden proteger de un ataque de inyecciones de SQL ya que garantizan que los valores recibidos desde un origen externo se pasen sólo como valores y no como parte de la instrucción Transact-SQL. Como resultado, los comandos Transact-SQL insertados en un valor no se ejecutan en el origen de datos. En cambio, se evalúan únicamente como un valor de parámetro. Para obtener más información sobre la validación de datos introducidos por el usuario en procedimientos de almacenamiento, vea Validar los datos proporcionados por el usuario.
El código siguiente muestra un ejemplo de la forma de utilizar un parámetro para pasar un valor. El tamaño definido para el parámetro es de 5 caracteres, de manera que si se envía un valor de cadena mayor en el control de TextBox se iniciará una excepción al añadir el parámetro al comando. Sin embargo, incluso si el tamaño es lo suficientemente grande como para albergar un fragmento de Transact-SQL malicioso, se trataría sólo como parte del valor, no como código Transact-SQL ejecutable. En este ejemplo, el control de excepciones se ha omitido para reducir el tamaño del código. Para obtener más información, vea Exception Handling and Logging más adelante en este mismo tema.
' Retrieve CustomerID to search for.
Dim ID As String = TextBox1.Text
Dim query As String = _
"SELECT * FROM Orders WHERE CustomerID = @CustomerID"
Dim cmd As SqlCommand = New SqlCommand(query, conn)
cmd.Parameters.Add("@CustomerID", SqlDbType.VarChar, 5).Value = ID
' Code connecting to a data source has been omitted for brevity.
Dim reader As SqlDataReader = cmd.ExecuteReader()
' Process results.
reader.Close()
// Retrieve CustomerID to search for.
string ID = TextBox1.Text;
string queryString = "SELECT * FROM Orders WHERE CustomerID = @CustomerID";
SqlCommand cmd = new SqlCommand(queryString, conn);
cmd.Parameters.Add("@CustomerID", SqlDbType.VarChar, 5).Value = ID;
// Code connecting to a data source has been omitted for brevity.
SqlDataReader reader = cmd.ExecuteReader();
' Process results.
reader.Close();
Control y registro de excepciones
Vea también