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

¿Entonces cree que su base de datos SQL es eficiente y está segura de la destrucción instantánea? Bueno, la inyección SQL no está de acuerdo!


Sí, estamos hablando de la destrucción instantánea, porque no quiero abrir este artículo con la terminología poco convincente de “reforzar la seguridad” y “evitar el acceso malicioso”. La inyección SQL es un truco tan antiguo en el libro que todos, todos los desarrolladores, lo saben muy bien y saben cómo prevenirlo. Excepto por ese extraño momento en que se deslizan, y los resultados pueden ser desastrosos.

Si ya sabe qué es la inyección SQL, no dude en pasar a la segunda mitad del artículo. Pero para aquellos que acaban de aparecer en el campo del desarrollo web y sueñan con asumir roles más altos, se requiere una introducción..

¿Qué es la inyección SQL??

La clave para entender la inyección SQL está en su nombre: inyección SQL +. La palabra “inyección” aquí no tiene ninguna connotación médica, sino que es el uso del verbo “inyectar”. Juntas, estas dos palabras transmiten la idea de poner SQL en una aplicación web.

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 maneje nuestra base de datos. Comprendamos eso con la ayuda de un ejemplo.

Supongamos que está creando un sitio web PHP típico para una tienda local de comercio electrónico, por lo que decide agregar un formulario de contacto como este:

Tu nombre

Tu mensaje

Y supongamos que el archivo send_message.php almacena todo en una base de datos para que los propietarios de la tienda puedan leer los mensajes de los usuarios más adelante. Puede tener un código como este:

<?php

$ nombre = $ _POST [‘nombre’];
$ mensaje = $ _POST [‘mensaje’];

// verifica si este usuario ya tiene un mensaje
mysqli_query ($ conn, "SELECCIONAR * de los mensajes donde nombre = $ nombre");

// Otro código aquí

Entonces, primero está tratando de ver si este usuario ya tiene un mensaje no leído. La consulta SELECT * de los mensajes donde name = $ name parece bastante simple, correcto?

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 en día, casi todas las aplicaciones lo hacen)
  • La conexión de la base de datos actual tiene permisos de “edición” y “eliminación” en la base de datos
  • Los nombres de las tablas importantes se pueden adivinar

El tercer punto significa que ahora que el atacante sabe que está ejecutando una tienda de comercio electrónico, es muy probable que esté almacenando los datos del pedido en una tabla de pedidos. Armado con todo esto, todo lo que el atacante debe hacer es proporcionar esto como su nombre:

Joe órdenes truncadas ;? ¡Sí señor! Veamos en qué se convertirá la consulta cuando se ejecute mediante el script PHP:

SELECCIONAR * DESDE mensajes DONDE nombre = Joe; truncar órdenes;

De acuerdo, la primera parte de la consulta tiene un error de sintaxis (sin comillas alrededor de “Joe”), pero el punto y coma obliga al motor MySQL a comenzar a interpretar uno nuevo: truncar órdenes. Solo 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:

  1. 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 adivina qué, incluso si eliminamos todos los privilegios de modificación, la inyección SQL 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.
  2. La entrada del usuario se está procesando. La única forma en que la inyección SQL puede funcionar es cuando acepta datos de usuarios. Una vez más, no es práctico detener todas las entradas para su aplicación solo porque le preocupa la inyección SQL.

Prevención de inyección SQL en PHP

Ahora, dado que las conexiones a la base de datos, las consultas y las entradas del usuario son parte de la vida, ¿cómo evitamos la inyección de SQL? Afortunadamente, es bastante simple, y hay dos formas de hacerlo: 1) desinfectar la entrada del usuario y 2) usar declaraciones preparadas.

Desinfectar la entrada del usuario

Si está utilizando una versión anterior de PHP (5.5 o inferior, y esto sucede mucho en el alojamiento compartido), es aconsejable ejecutar toda su entrada de usuario a través de una función llamada mysql_real_escape_string (). Básicamente, lo que hace es eliminar todos los caracteres especiales en una cadena para que pierdan su significado cuando son utilizados por la base de datos..

Por ejemplo, si tiene una cadena como “Soy una cadena”, un atacante puede utilizar el carácter de comillas simples (‘) para manipular la consulta de la base de datos que se está creando y provocar una inyección de SQL. Ejecutarlo a través de mysql_real_escape_string () produce Soy una cadena, que agrega una barra diagonal inversa a la comilla simple, escapándola. Como resultado, toda la cadena ahora se pasa como una cadena inofensiva a la base de datos, en lugar de poder participar en la manipulación de consultas.

Hay un inconveniente con este enfoque: es una técnica muy, muy antigua que acompaña las formas más antiguas de acceso a la base de datos en PHP. A partir de PHP 7, esta función ya no existe, lo que nos lleva a nuestra próxima solución.

Use declaraciones preparadas

Las declaraciones preparadas son una forma de hacer consultas a la base de datos de manera más segura y confiable. La idea es que, en lugar de enviar la consulta sin procesar a la base de datos, primero le digamos a la base de datos la estructura de la consulta que enviaremos. Esto es lo que queremos decir con “preparar” una declaración. Una vez que se prepara una declaración, 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, haciendo que sean tratadas como meras variables (o cargas útiles, si lo desea) en todo el proceso. Así son las declaraciones preparadas:

<?php
$ servername = "localhost";
$ username = "nombre de usuario";
$ contraseña = "contraseña";
$ dbname = "myDB";

// Crear conexión
$ conn = new mysqli ($ nombre de servidor, $ nombre de usuario, $ contraseña, $ dbname);

// Verifica la conexión
if ($ conn->connect_error) {
morir("La conexión falló: " . $ conn->connect_error);
}

// preparar y atar
$ stmt = $ conn->preparar("INSERTAR EN MyGuests (nombre, apellido, correo electrónico) VALORES (?,?,?)");
$ stmt->bind_param ("sss", $ nombre, $ apellido, $ correo electrónico);

// establece parámetros y ejecuta
$ nombre = "Juan";
$ apellido = "Gama";
$ email = "[correo electrónico protegido]";
$ stmt->ejecutar();

$ nombre = "María";
$ apellido = "Moe";
$ email = "[correo electrónico protegido]";
$ stmt->ejecutar();

$ nombre = "Julie";
$ apellido = "Dooley";
$ email = "[correo electrónico protegido]";
$ stmt->ejecutar();

eco "Nuevos registros creados exitosamente";

$ stmt->cerca();
$ conn->cerca();
?>

Sé que el proceso suena innecesariamente complejo si eres nuevo en las declaraciones preparadas, pero el concepto bien vale la pena.. Aqui esta una buena introducción.

Para aquellos que ya están familiarizados con la extensión PDO de PHP y la usan para crear declaraciones preparadas, tengo un pequeño consejo.

Advertencia: tenga cuidado al configurar PDO

Cuando usamos PDO para acceder a la base de datos, podemos dejarnos llevar por una falsa sensación de seguridad. “Ah, bueno, estoy usando PDO. Ahora no necesito pensar en otra cosa “, así es como va nuestro pensamiento en general. Es cierto que PDO (o declaraciones preparadas por MySQLi) es suficiente para prevenir todo tipo de ataques de inyección SQL, pero debe tener cuidado al configurarlo. Es común simplemente copiar y pegar código de tutoriales o de sus proyectos anteriores y seguir adelante, pero esta configuración puede deshacer todo:

$ dbConnection->setAttribute (PDO :: ATTR_EMULATE_PREPARES, verdadero);

Lo que hace esta configuración es decirle a PDO que emule declaraciones preparadas en lugar de usar realmente la función de declaraciones preparadas 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 declaraciones preparadas y estableciendo 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é establecida en falso.

$ dbConnection->setAttribute (PDO :: ATTR_EMULATE_PREPARES, falso);

Ahora el script PHP se ve obligado a usar declaraciones preparadas a nivel de base de datos, evitando todo tipo de inyección SQL.

Prevenir el uso de 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 la capa 7, como secuencias de comandos entre sitios, autenticación interrumpida, falsificación entre sitios, exposición de datos, etc. Puede usar autohospedado como Mod Security o basado en la nube de la siguiente manera.

Inyección SQL y marcos PHP modernos

La inyección SQL es tan común, tan fácil, tan frustrante y tan peligrosa que todos los marcos web PHP modernos vienen incorporados con contramedidas. En WordPress, por ejemplo, tenemos el $ wpdb->la función prepare (), mientras que si está utilizando un marco MVC, hace todo el trabajo sucio por usted y ni siquiera tiene que pensar en prevenir la inyección de SQL. Es un poco molesto que en WordPress tengas que preparar declaraciones explícitamente, pero bueno, estamos hablando de WordPress. ��

De todos modos, mi punto es que la generación 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 una puerta trasera abierta en su aplicación (tal vez es un parámetro de consulta $ _GET y los viejos hábitos de iniciar una consulta sucia), los resultados pueden ser catastróficos. Por lo tanto, siempre es mejor tomarse el tiempo para sumergirse más profundamente en los cimientos.

Conclusión

La inyección SQL es un ataque muy desagradable en una aplicación web, pero se evita fácilmente. Como vimos en este artículo, tener cuidado al procesar la entrada del usuario (por cierto, la inyección de 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 estamos trabajando en la seguridad de un marco web, por lo que es mejor estar al tanto de este tipo de ataque y no caer en él..

Jeffrey Wilson Administrator
Sorry! The Author has not filled his profile.
follow me
    Like this post? Please share to your friends:
    Adblock
    detector
    map