Los últimos tutoriales de desarrollo web
 

SQL Inyección


Una Inyección SQL puede destruir su base de datos.


SQL en páginas Web

En los capítulos anteriores, que han aprendido a recuperar datos de bases de datos (y actualización), el uso de SQL.

Cuando SQL se utiliza para mostrar datos en una página web, es común para que los usuarios de Internet de entrada de sus propios valores de búsqueda.

Como las sentencias SQL son de sólo texto, es fácil, con un pequeño pedazo de código de computadora, para cambiar dinámicamente las sentencias SQL para proporcionar al usuario con los datos seleccionados:

servidor de códigos

txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;

El ejemplo anterior, crea una instrucción de selección mediante la adición de una variable (txtUserId) a una cadena de selección. La variable se obtiene de la entrada del usuario (Request) a la página.

El resto de este capítulo se describen los peligros potenciales de la utilización de la entrada del usuario en las instrucciones SQL.


Inyección SQL

la inyección de SQL es una técnica en la que los usuarios maliciosos pueden inyectar comandos SQL en una sentencia de SQL, a través de entrada página web.

comandos SQL inyectados pueden alterar instrucción SQL y poner en peligro la seguridad de una aplicación web.


Inyección SQL Basado en 1 = 1 siempre es cierto

Mira el ejemplo anterior, una vez más.

Digamos que el propósito original del código era crear una instrucción SQL para seleccionar un usuario con un identificador de usuario dado.

Si no hay nada para evitar que un usuario la entrada al "wrong" de entrada, el usuario puede introducir algún "smart" de entrada de la siguiente manera:

Identidad de usuario:

Resultado del servidor

SELECT * FROM Users WHERE UserId = 105 or 1=1

El SQL anterior es válido. Se devolverá todas las filas de la tabla de usuarios, ya que 1 = 1 es siempre cierto.

¿El ejemplo anterior parece peligroso? ¿Qué pasa si la tabla de usuarios contiene los nombres y contraseñas?

La sentencia SQL anterior es mucho lo mismo que esto:

SELECT UserId, Name, Password FROM Users WHERE UserId = 105 or 1=1

Un hacker inteligente podría obtener acceso a todos los nombres de usuario y contraseñas en una base de datos con sólo insertar 105 o 1 = 1 en la casilla correspondiente.


Inyección SQL Sobre la base de ""="" siempre es cierto

Aquí es una construcción común, que se utiliza para verificar la conexión del usuario a un sitio web:

Nombre de usuario:

Contraseña:

servidor de códigos

uName = getRequestString("UserName");
uPass = getRequestString("UserPass");

sql = "SELECT * FROM Users WHERE Name ='" + uName + "' AND Pass ='" + uPass + "'"

Un hacker inteligente podría obtener acceso a los nombres de usuario y contraseñas en una base de datos con sólo insertar "o ""=" en el cuadro de texto nombre de usuario o contraseña.

El código en el servidor creará una instrucción SQL válida la siguiente manera:

Resultado

SELECT * FROM Users WHERE Name ="" or ""="" AND Pass ="" or ""=""

El resultado es válido SQL. Se devolverá todas las filas de la tabla de usuarios, desde donde "" = "" es siempre cierto.


La inyección SQL Con base en instrucciones SQL por lotes

La mayoría de las bases de datos compatibles con SQL por lotes, separados por punto y coma.

Ejemplo

SELECT * FROM Users; DROP TABLE Suppliers

El SQL anterior devolverá todas las filas en la tabla de usuarios y, a continuación, elimine la tabla llamados Proveedores.

Si tuviéramos el siguiente código de servidor:

servidor de códigos

txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;

Y la siguiente entrada:

Identidad de usuario:

El código en el servidor crearía una instrucción SQL válida la siguiente manera:

Resultado

SELECT * FROM Users WHERE UserId = 105; DROP TABLE Suppliers

Parámetros para la Protección

Algunos desarrolladores web utilizan una "blacklist" de las palabras o caracteres que desea buscar en la entrada de SQL, para evitar ataques de inyección SQL.

Esta no es una idea muy buena. Muchas de estas palabras (como eliminar o gota) y caracteres (como puntos y comas y comillas), se utilizan en el lenguaje común, y debe ser permitido en muchos tipos de entrada.

(En realidad debería ser perfectamente legal para introducir una instrucción SQL en un campo de base de datos.)

La única manera probada para proteger un sitio web desde los ataques de inyección SQL, es utilizar los parámetros de SQL.

los parámetros de SQL son valores que se agregan a una consulta SQL en tiempo de ejecución, de una manera controlada.

Ejemplo ASP.NET Razor

txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = @0";
db.Execute(txtSQL,txtUserId);

Tenga en cuenta que los parámetros están representados en la instrucción SQL por un marcador @.

El motor de SQL comprueba cada parámetro para asegurarse de que es correcta para su columna y son tratados literalmente, y no como parte del SQL para su ejecución.

Otro ejemplo

txtNam = getRequestString("CustomerName");
txtAdd = getRequestString("Address");
txtCit = getRequestString("City");
txtSQL = "INSERT INTO Customers (CustomerName,Address,City) Values(@0,@1,@2)";
db.Execute(txtSQL,txtNam,txtAdd,txtCit);

Usted acaba de aprender a evitar la inyección de SQL. Una de las principales vulnerabilidades de sitios web.


Ejemplos

Los siguientes ejemplos muestran cómo construir consultas con parámetros en algunos lenguajes web comunes.

Instrucción SELECT de ASP.NET:

txtUserId = getRequestString("UserId");
sql = "SELECT * FROM Customers WHERE CustomerId = @0";
command = new SqlCommand(sql);
command.Parameters.AddWithValue("@0",txtUserID);
command.ExecuteReader();

INSERT INTO en ASP.NET:

txtNam = getRequestString("CustomerName");
txtAdd = getRequestString("Address");
txtCit = getRequestString("City");
txtSQL = "INSERT INTO Customers (CustomerName,Address,City) Values(@0,@1,@2)";
command = new SqlCommand(txtSQL);
command.Parameters.AddWithValue("@0",txtNam);
command.Parameters.AddWithValue("@1",txtAdd);
command.Parameters.AddWithValue("@2",txtCit);
command.ExecuteNonQuery();

INSERT INTO en PHP:

$stmt = $dbh->prepare("INSERT INTO Customers (CustomerName,Address,City)
VALUES (:nam, :add, :cit)");
$stmt->bindParam(':nam', $txtNam);
$stmt->bindParam(':add', $txtAdd);
$stmt->bindParam(':cit', $txtCit);
$stmt->execute();