¿Qué es la inyección SQL y cómo realizarla?revent en aplicaciones PHP?

Entonces, ¿cree que su base de datos SQL es eficaz y está a salvo de la destrucción instantánea? Bueno, ¡SQL Injection no está de acuerdo!
Sí, estamos hablando de destrucción instantánea, porque no quiero abrir este artículo con la habitual y poco convincente terminología de “reforzar la seguridad” y “preventrar en acceso malicioso”. SQL Injection Es un truco tan antiguo que todos, todos los desarrolladores, lo conocen muy bien y saben muy bien cómo p.revEntrégalo. Excepto por ese momento extraño en el que cometen un desliz y los resultados pueden ser nada menos que desastrosos.
Si ya sabe qué es SQL Injection, no dude en pasar a la segunda mitad del artículo. Pero para aquellos que recién están surgiendo en el campo del desarrollo web y sueñan con asumir roles más altos, es necesario hacer alguna introducción.
¿Qué es la inyección SQL?
The key to understanding SQL Injection is in its name: SQL + Injection. The word “injection” here doesn’t have any medical connotations, but rather is the usage of the verb “inject.” Together, these two words convey the idea of putting SQL into a web application.
Poner SQL en una aplicación web. . . hmmm. . . ¿No es eso lo que estamos haciendo de todos modos? Sí, pero no queremos que un atacante controle nuestra base de datos. Entendamos eso con la ayuda de un ejemplo.
Supongamos que está creando un sitio web PHP típico para una tienda de comercio electrónico local, por lo que decide agregar un formulario de contacto como este:
<form action="record_message.php" method="POST">
<label>Your name</label>
<input type="text" name="name">
<label>Your message</label>
<textarea name="message" rows="5"></textarea>
<input type="submit" value="Send">
</form>
Y asumamos el archivo send_message.php
stores everything in a database so that the store owners can read user messages later on. It may have some code like this:
<?php
$name = $_POST['name'];
$message = $_POST['message'];
// check if this user already has a message
mysqli_query($conn, "SELECT * from messages where name = $name");
// Other code here
Entonces, primero está tratando de ver si este usuario ya tiene un mensaje no leído. La consulta SELECT * from messages where name = $name
parece bastante simple, ¿verdad?
¡INCORRECTO!
En nuestra inocencia, hemos abierto las puertas a la destrucción instantánea de nuestra base de datos. Para que esto suceda, el atacante debe cumplir las siguientes condiciones:
- La aplicación se ejecuta en una base de datos SQL (hoy, casi todas las aplicaciones lo están)
- La conexión de la base de datos actual tiene permisos de "editar" y "eliminar" en la base de datos
- Los nombres de las tablas importantes se pueden adivinar
El third punto significa que ahora que el atacante sabe que usted está ejecutando una tienda de comercio electrónico, es muy probable que esté almacenando los datos del pedido en un orders
mesa. Armado con todo esto, todo lo que el atacante necesita hacer es proporcionar esto como su nombre:
Joe; truncate orders;
? ¡Sí señor! Veamos en qué se convertirá la consulta cuando sea ejecutada por el script PHP:
SELECT * FROM messages WHERE name = Joe; truncate orders;
De acuerdo, la primera parte de la consulta tiene un error de sintaxis (no hay comillas alrededor de "Joe"), pero el punto y coma obliga al motor MySQL a comenzar a interpretar uno nuevo: truncate orders
. Así, de una sola vez, ¡todo el historial de pedidos se ha ido!
Ahora que sabe cómo funciona la inyección SQL, es hora de ver cómo detenerla. Las dos condiciones que deben cumplirse para una inyección SQL exitosa son:
- El script PHP debe tener privilegios de modificación / eliminación en la base de datos. Creo que esto es cierto para todas las aplicaciones y no podrá hacer que sus aplicaciones sean de solo lectura. 🙂 Y adivinen qué, incluso si eliminamos todos los privilegios de modificación, la inyección SQL aún puede permitir que alguien ejecute consultas SELECT y vea toda la base de datos, incluidos los datos confidenciales. En otras palabras, reducir el nivel de acceso a la base de datos no funciona y su aplicación lo necesita de todos modos.
- La entrada del usuario está siendo processed. La única forma en que puede funcionar la inyección SQL es cuando se aceptan datos de los usuarios. Una vez más, no es práctico detener todas las entradas de su aplicación sólo porque le preocupa la inyección SQL.
PrevIntroducir la inyección SQL en PHP
Ahora bien, dado que las conexiones a bases de datos, las consultas y las entradas de los usuarios son parte de la vida, ¿cómo podemos p?rev¿Inyección SQL? Afortunadamente, es bastante simple y hay dos formas de hacerlo: 1) desinfectar la entrada del usuario y 2) usar st preparado.atementos.
Desinfectar la entrada del usuario
Si está utilizando una versión anterior de PHP (5.5 o inferior, y esto sucede con frecuencia en alojamiento compartido), es wise para ejecutar toda la entrada de usuario a través de una función llamada mysql_real_escape_string()
. Básicoally, lo que hace es eliminar todos los caracteres especiales de una cadena para que pierdan su significado cuando los utilice la base de datos.
Por ejemplo, si tiene una cadena como I'm a string
, un atacante puede utilizar la comilla simple (') para manipularate la consulta de la base de datos se creaated y provocar una inyección SQL. Ejecutándolo mysql_real_escape_string()
produce I\'m a string
, que agrega una barra invertida a la comilla simple, escapándola. Como resultado, la cadena completa ahora se pasa como una cadena inofensiva a la base de datos, en lugar de poder participar.ate en la manipulación de consultas.
Hay un inconveniente con este enfoque: es una really, really Técnica antigua que va junto con las formas más antiguas de acceso a bases de datos en PHP. A partir de PHP 7, esta función ya no existe, lo que nos lleva a nuestra siguiente solución.
Utilice st preparadoatementos
st preparadoateLos comentarios son una forma de hacer que las consultas a la base de datos sean más seguras y confiables. La idea es que en lugar de enviar la consulta sin formato a la base de datos, primero le decimos a la base de datos la estructura de la consulta que enviaremos. Esto es lo que queremos decir con “preparar” una st.atemento. Una vez al díaateCuando se prepara el proceso, pasamos la información como entradas parametrizadas para que la base de datos pueda "llenar los vacíos" conectando las entradas a la estructura de consulta que enviamos antes. Esto elimina cualquier potencia especial que puedan tener las entradas, lo que hace que sean tremendas.ated como meras variables (o cargas útiles, por así decirlo) en todo el process. Esto es lo que preparó st.ateLos comentarios se ven así:
<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// prepare and bind
$stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $firstname, $lastname, $email);
// set parameters and execute
$firstname = "John";
$lastname = "Doe";
$email = "john@example.com";
$stmt->execute();
$firstname = "Mary";
$lastname = "Moe";
$email = "mary@example.com";
$stmt->execute();
$firstname = "Julie";
$lastname = "Dooley";
$email = "julie@example.com";
$stmt->execute();
echo "New records created successfully";
$stmt->close();
$conn->close();
?>
Sé que el process Suena innecesariamente complejo si eres nuevo en el mundo de la preparación.atepero el concepto bien vale la pena. effort. Esto es a nice introducción al mismo.
Para aquellos que ya están familiarizados con la extensión PDO de PHP y la utilizan para crearate st preparadoatementos, tengo un pequeño consejo.
Advertencia: tenga cuidado al configurar PDO
Cuando utilizamos PDO para acceder a bases de datos, podemos dejarnos atrapar por una falsa sensación de seguridad. “Ah, bueno, estoy usando PDO. Ahora no necesito pensar en nada más”: así es como se genera nuestro pensamiento.ally va. Es cierto que PDO (o MySQLi preparó statementos) es suficiente para prevPermite todo tipo de ataques de inyección SQL, pero debes tener cuidado al configurarlo. Es común simplemente copiar y pegar código de tutoriales o de proyectos anteriores y continuar, pero esta configuración puede deshacer todo:
$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
Lo que hace esta configuración es decirle a PDO que emuleate st preparadoatementos en lugar de accionesally use el st preparadoatefunción de comentarios de la base de datos. En consecuencia, PHP envía cadenas de consulta simples a la base de datos incluso si su código parece estar creando archivos preparados.ateajustes y configuración de parámetros y todo eso. En otras palabras, eres tan vulnerable a la inyección SQL como antes. 🙂
La solución es simple: asegúrese de que esta emulación esté configurada como falsa.
$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
Ahora el script PHP se ve obligado a utilizar st preparadoatementos a nivel de base de datos, preventrando todo tipo de inyección SQL.
Preventrar usando WAF
¿Sabe que también puede proteger las aplicaciones web de la inyección de SQL utilizando WAF (firewall de aplicaciones web)?
Bueno, no solo la inyección SQL, sino muchas otras vulnerabilidades de capa 7, como secuencias de comandos entre sitios, autenticación rota, falsificación entre sitios, exposición de datos, etc. self-alojado como Seguridad Mod o basado en la nube como el siguiente.
Inyección SQL y frameworks PHP modernos
La inyección SQL es tan común, tan fácil, tan frustrante y tan peligrosa que todos los Marcos web PHP vienen incorporados con contramedidas. En WordPress, por ejemplo, tenemos el $wpdb->prepare()
función, mientras que si estás usando un marco MVC, hace todo el trabajo sucio por ti y ni siquiera tienes que pensar en previntroducir inyección SQL. Es un poco molesto que en WordPress tengas que preparar stateMenciona explícitamente, pero bueno, estamos hablando de WordPress. 🙂
De todos modos, mi punto es que la raza moderna de desarrolladores web no tiene que pensar en la inyección de SQL y, como resultado, ni siquiera son conscientes de la posibilidad. Como tal, incluso si dejan uno puerta trasera abrir en su aplicación (tal vez sea un parámetro de consulta $_GET y antiguo jabit(en lugar de lanzar una consulta sucia), los resultados pueden ser catastróficos. Por eso siempre es mejor tomarse el tiempo para profundizar en los cimientos.
Conclusión
La inyección SQL es un ataque muy desagradable a una aplicación web, pero se puede evitar fácilmente. Como vimos en este artículo, tener cuidado al processing la entrada del usuario (por cierto, la inyección SQL no es la única amenaza que conlleva el manejo de la entrada del usuario) y consultar la base de datos es todo lo que hay que hacer. Dicho esto, no siempre trabajamos en la seguridad de un framework web, por lo que es mejor estar atento a este tipo de ataques y no caer en él.