La inyección SQL es una vulnerabilidad de seguridad crítica que se encuentra habitualmente en las aplicaciones web, sobre todo en las desarrolladas con PHP y que interactúan con una base de datos backend.
Este ataque permite a usuarios no autorizados manipular datos o ejecutar comandos en el servidor, por lo que la prevención en PHP es esencial para la seguridad de las aplicaciones web.
Al evitar las inyecciones SQL, los desarrolladores de PHP pueden salvaguardar eficazmente los datos sensibles
En este artículo, exploraremos las causas de la inyección SQL y discutiremos las medidas de seguridad para prevenirla en aplicaciones web desplegadas en varios servidores de alojamiento web PHP.
Optimiza el rendimiento de tu base de datos con Cloudways
Regístrate ahora y domina el arte de conectar bases de datos MySQL con alojamiento PHP ¡hoy mismo!
¿Qué es la inyección SQL?
La Inyección SQL es una técnica utilizada por los hackers para cambiar las sentencias SQL que se ejecutan en el backend de los comandos SQL ejecutados falsamente. Estas inyecciones suelen realizarse a través de los campos de entrada del formulario, causando un mal efecto en la base de datos. Esto provoca la pérdida de información sensible de la base de datos.
Mediante estas tácticas, los atacantes introducen datos vulnerables en un intérprete SQL que ejecuta comandos no deseados. Utilizando tales inyecciones PHP MySQL, los atacantes pueden insertar, actualizar o incluso borrar datos de la base de datos.
Hace poco se produjo un ataque en el que un grupo de piratas informáticos, ResumeLooters, robó más de dos millones de direcciones de correo electrónico y datos personales de 65 sitios web mediante inyección SQL. Su objetivo eran sitios de venta al por menor y de contratación, lo que pone de manifiesto la necesidad de adoptar medidas de seguridad sólidas para evitar este tipo de violaciones.
Seguir un enfoque de Desarrollo Orientado a Pruebas (TDD ) en el desarrollo de software puede mejorar la calidad del código y reducir la probabilidad de ciertos tipos de errores, incluidas las vulnerabilidades.
Dentro de un rato veremos las soluciones para evitar la inyección SQL en PHP. Para que lo sepas, si eres cliente de Cloudways, no tienes que preocuparte por las vulnerabilidades, ya que ofrecemos un cortafuegos dedicado a nivel de servidor, protección automatizada con Fail2ban, parches de seguridad y actualizaciones periódicas, protección contra bots, escáner de vulnerabilidades (WP) y mucho más.
Leer más sobre: Guía Definitiva de Buenas Prácticas de Seguridad en PHP
¿Qué es el TDD?
El Desarrollo Orientado a Pruebas (TDD) es una práctica en la que escribes una prueba antes de escribir el código correspondiente. Este enfoque garantiza que el código está diseñado para cumplir los requisitos descritos en la prueba.
Al escribir primero los casos de prueba, los desarrolladores pueden identificar posibles fallos al principio del proceso de desarrollo. El ciclo suele consistir en escribir una prueba que falla, escribir la cantidad mínima de código necesaria para superar la prueba y, a continuación, refactorizar el código para mejorar su diseño, al tiempo que se garantiza que todas las pruebas siguen superándose.
Este proceso iterativo ayuda a mejorar la calidad del código y a reducir el número de errores encontrados durante el desarrollo.
Echa un vistazo a la siguiente representación visual del proceso de TDD:

¿Qué causa la inyección SQL?
Al codificar, debemos seguir las mejores prácticas para evitar la inyección SQL en PHP. Algunas de las causas que pueden afectar a estos ataques son:
- Caracteres de espacio filtrados incorrectamente
- Manejo incorrecto del tipo
- Pasar datos no desinfectados a la BD
- No utilizar la codificación Unicode completa
- Mezcla del código y los datos.
- Uso de comillas para delimitar cadenas
Estas son algunas de las causas que debes tener en cuenta al codificar para evitar las inyecciones SQL.
Veamos los ejemplos
El siguiente ejemplo de inyección SQL en PHP te ayudará a comprender mejor el concepto de inyecciones SQL:
Ejemplo nº 1
Supón que hay un formulario que contiene dos campos de texto: uno para el nombre de usuario y otro para la contraseña, junto con un botón de inicio de sesión. El código PHP del backend será el siguiente:
<?php $userName=$_POST['userName']; $password=$_POST['password']; $sqlQuery="SELECT * FROM users WHERE user_name='".$username."' AND user_password='".$password"';"; ?>
El código anterior contiene una laguna. Si un usuario introduce ‘ o ‘a’=’a’ ‘o’, entonces la variable $contraseña tendrá el valor ‘ o ‘a’=’a’ ‘o’.
De este modo, la consulta anterior se actualizará como:
<?php $sqlQuery="SELECT * FROM users WHERE user_name='".$username."' AND user_password='' or 'a'='a';"; ?>
En el ejemplo anterior, la afirmación «a=a» siempre es verdadera. Por lo tanto, la condición se cumple sin necesidad de que coincida la contraseña real, lo que da lugar a posibles vulnerabilidades de seguridad.
Solución para el Ejemplo nº 1: Utilizar Consultas Parametrizadas
Las consultas parametrizadas son sentencias SQL predefinidas que incluyen marcadores de posición para la entrada del usuario. Cuando se ejecutan, estas consultas aceptan la entrada real del usuario por separado.
Las consultas parametrizadas están ampliamente soportadas en varias interfaces de bases de datos y frameworks PHP (como PDO y mysqli), lo que mejora la seguridad de las aplicaciones frente a intentos de inyección SQL.
Incorporar consultas parametrizadas es crucial para reforzar las aplicaciones PHP contra la inyección SQL. Al segregar las sentencias SQL y las entradas del usuario, estas consultas mitigan eficazmente los posibles ataques de inyección.
Así:
<?php
$pdo = new PDO("mysql:host=localhost;dbname=mydatabase", "username", "password");
// Define the SQL query with placeholders
$sql = "SELECT * FROM users WHERE username = :username AND password = :password";
// Prepare the statement
$stmt = $pdo->prepare($sql);
Después de preparar la declaración, vinculamos los valores reales de entrada del usuario a los marcadores de posición:
$username = $_POST["username"];
$password = $_POST["password"];
// Bind values to placeholders
$stmt->bindParam(":username", $username, PDO::PARAM_STR);
$stmt->bindParam(":password", $password, PDO::PARAM_STR);
Aquí, bindParam vincula las variables $username y $password a sus correspondientes marcadores de posición. Para mejorar la seguridad, también especificamos el tipo de datos (PDO::PARAM_STR para cadena).
Por último, ejecutamos la sentencia preparada con los valores vinculados:
$stmt->execute(); // Fetch results (if applicable) $user = $stmt->fetch(PDO::FETCH_ASSOC);
Tras implementar las consultas parametrizadas, la aplicación PHP salvaguarda eficazmente los datos del usuario, reforzando sus defensas contra los riesgos de inyección SQL.
Ejemplo nº 2
En la programación SQL, a menudo construimos consultas de forma dinámica añadiendo datos sobre la marcha. Estos datos pueden estropear nuestra consulta si no se manejan adecuadamente, como demuestran los ejemplos de inyección SQL, especialmente en configuraciones PHP/MySQL.
Por ejemplo, considera esta consulta regular:
$expected_data = 1; $query = "SELECT * FROM users where id=$expected_data";
Esto nos da una consulta regular:
SELECT * FROM users where id=1
Ahora, introduzcamos algunos datos problemáticos:
$spoiled_data = "1; DROP TABLE users;"; $query = "SELECT * FROM users where id=$spoiled_data";
Esto da lugar a una secuencia maliciosa:
SELECT * FROM users where id=1; DROP TABLE users;
El problema surge porque estamos añadiendo datos directamente a la consulta, convirtiéndola de hecho en parte del programa. Dependiendo de los datos añadidos, podríamos obtener una salida normal o consecuencias no deseadas, como la eliminación de una tabla.
Solución para el Ejemplo nº 2: Utilizar Objetos de Datos PHP (PDO)
Evitar la inyección SQL en PHP, especialmente cuando se utiliza PDO (PHP Data Objects), es crucial para garantizar la seguridad de tus aplicaciones. PDO proporciona sentencias preparadas, que son potentes herramientas para defenderse de los ataques de inyección SQL.
Puedes seguir estos pasos cuando utilices PDO. Primero, establece una conexión PDO con tu base de datos:
<?php
$host = 'your_host';
$dbname = 'your_database';
$username = 'your_username';
$password = 'your_password';
// Establish PDO connection
try {
$pdo = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
// Set PDO to throw exceptions on error
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Error connecting to database: " . $e->getMessage());
}
?>
Las sentencias preparadas son sentencias SQL precompiladas por el servidor de bases de datos. Te permiten separar el código SQL de los datos, evitando eficazmente los ataques de inyección SQL. A continuación te explicamos cómo puedes utilizar sentencias preparadas con PDO:
<?php
// Assume $userInput is coming from user input (e.g., form submission)
$userInput = $_POST['username'];
// Prepare a SQL statement with a placeholder
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username");
// Bind the parameter to the placeholder
$stmt->bindParam(':username', $userInput);
// Execute the prepared statement
$stmt->execute();
// Fetch the results
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Use the results as needed
foreach ($results as $row) {
echo "Username: " . $row['username'] . "<br>";
}
?>
Utilizando sentencias preparadas y vinculación de parámetros, puedes prevenir eficazmente los ataques de inyección SQL en tus aplicaciones PHP.
Protege tus datos con el alojamiento PHP de Cloudways
Protege tus datos con las copias de seguridad automáticas de Cloudways, la sólida protección del cortafuegos y la monitorización en tiempo real. ¡Contrata ahora el mejor Hosting PHP!
Cómo Evitar la Inyección SQL en PHP – Paso a Paso
Para evitar la inyección SQL en PHP, puedes seguir un enfoque exhaustivo paso a paso que incluya la validación de entradas, las sentencias preparadas y la gestión adecuada de los resultados de las consultas. Aquí tienes una guía detallada:
Paso 1: Validar la entrada
Antes de procesar cualquier entrada de usuario, valídala y desinféctala para asegurarte de que cumple los requisitos de tu aplicación y es segura para las operaciones de la base de datos.
$username = isset($_POST['username']) ? $_POST['username'] : '';
// Validate input (e.g., check if it's not empty, contains valid characters, etc.)
if (empty($username)) {
// Handle validation failure (e.g., show error message)
die("Username is required.");
}
// You can apply further validation as needed...
Paso 2: Preparar una consulta
Construye tu consulta SQL como una cadena, asegurándote de que no contiene ningún dato proporcionado por el usuario. Utiliza marcadores de posición (? o marcadores de posición con nombre como nombre de usuario) en lugar de incrustar directamente la entrada del usuario.
$sql = "SELECT * FROM users WHERE username = ?";
Paso 3: Crear la Declaración Preparada
Crea una sentencia preparada utilizando PDO para compilar la consulta SQL en el servidor de la base de datos. Este paso prepara la sentencia SQL para su ejecución, separando la lógica SQL de los datos.
$stmt = $pdo->prepare($sql);
Paso 4: Vincular los parámetros a la declaración preparada
Vincula la entrada validada del usuario a los marcadores de posición de la sentencia preparada. Este proceso gestiona automáticamente el escape adecuado y evita la inyección SQL.
$stmt->bindParam(1, $username, PDO::PARAM_STR);
// You can also use named placeholders:
// $stmt->bindParam(':username', $username, PDO::PARAM_STR);
Paso 5: Ejecuta tu consulta
Tras preparar la sentencia SQL y vincular de forma segura los parámetros a los marcadores de posición, ejecuta la sentencia preparada utilizando el método execute(). Este paso sustituye los parámetros vinculados de forma segura en la consulta SQL en el momento de la ejecución.
$stmt->execute();
Paso 6: Obtener el resultado
Este paso consiste en obtener el conjunto de resultados de la sentencia SQL ejecutada utilizando los métodos de obtención adecuados que ofrece PDO.
// Fetch the result set into an associative array
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Process the results, if any
foreach ($results as $row) {
// Output each username from the result set
echo "Username: " . $row['username'] . "<br>";
}
En este fragmento de código
- fetchAll(PDO::FETCH_ASSOC) recupera todas las filas del conjunto de resultados en una matriz asociativa. Cada elemento de la matriz corresponde a una fila del conjunto de resultados, con los nombres de las columnas como claves.
- El bucle foreach itera sobre cada fila del conjunto de resultados.
- Dentro del bucle, $row[‘ nombredeusuario ‘] accede al valor de la columna ‘nombredeusuario ‘ de cada fila, que luego se repite para darle salida.
Paso 7: Valida tu solicitud
Realiza una validación y pruebas exhaustivas de tu aplicación para asegurarte de que toda la validación de entrada, las consultas SQL y la gestión de salida son seguras y funcionan correctamente. Revisa y actualiza periódicamente tus prácticas de seguridad para mitigar los riesgos potenciales.
¿Cómo puede Cloudways ayudar a mitigar los ataques de inyección SQL?
Cloudways ofrece varias funciones que pueden ayudar a mitigar las amenazas a la seguridad de tu servidor, entre ellas:
Mitigación DDoS de Capa 3 y 4: Protege tu servidor de las inundaciones de tráfico malicioso que podrían acabar con tu sitio web. Cloudways colabora con los mejores proveedores de cloud computing para hacer frente a estos ataques antes de que lleguen a tu servidor.
Cortafuegos dedicado a nivel de servidor: El cortafuegos a nivel de servidor puede configurarse para bloquear los intentos de acceso no autorizados, incluidos los destinados a explotar vulnerabilidades de inyección SQL.
Protección automatizada con Fail2ban: Fail2ban supervisa los intentos de inicio de sesión y puede bloquear automáticamente las actividades sospechosas, incluidas las indicativas de intentos de inyección SQL.
Integración con Patchstack: Cloudways se integra con Patchstack, un escáner de vulnerabilidades que comprueba continuamente tus aplicaciones en busca de puntos débiles.
Parches de seguridad periódicos: Cloudways mantiene actualizado el software subyacente del servidor con los últimos parches de seguridad, que corrigen las vulnerabilidades identificadas por los proveedores de sistemas operativos.
Protección contra bots: Aunque están dirigidos principalmente al tráfico de bots, los mecanismos de protección contra bots también pueden ayudar a mitigar los ataques automatizados de inyección SQL.
Escáner de vulnerabilidades (WP): La colaboración Patchstack proporciona un escáner de vulnerabilidades que puede detectar y alertarte de posibles vulnerabilidades de inyección SQL en el núcleo de WordPress, plugins o temas.
Conclusión
Mantenerse a salvo de los ataques de inyección SQL es crucial, ya que los atacantes pueden saltarse las medidas de seguridad de las aplicaciones y utilizar consultas SQL para modificar, añadir, actualizar o eliminar registros de una base de datos.
En esta guía, hemos tratado soluciones prácticas para evitar la inyección SQL en PHP, haciendo hincapié en las consultas parametrizadas y en los Objetos de Datos PHP (PDO).
También hemos esbozado un enfoque paso a paso para evitar la inyección SQL en PHP, que abarca la validación de entradas, las sentencias preparadas y el manejo seguro de consultas.
Además, hemos destacado cómo Cloudways ofrece funciones de seguridad como mitigación de DDoS, cortafuegos, Fail2ban, parches y escaneado de vulnerabilidades. Aplicando estas medidas, los desarrolladores pueden reducir los riesgos de inyección SQL y garantizar la integridad de los datos.
¿Tienes preguntas? No dudes en preguntar en la sección de comentarios de abajo.
P) ¿Qué es la inyección SQL en PHP?
A) La Inyección SQL es un tipo de ataque de inyección de código que se produce cuando se utilizan entradas de usuario no validadas para crear dinámicamente sentencias SQL. Esto puede conducir a un acceso no autorizado o a la manipulación de la información de la base de datos, lo que plantea importantes riesgos de seguridad.
P) ¿Por qué la Inyección SQL es una amenaza importante?
A) La Inyección SQL puede provocar filtraciones de datos, accesos no autorizados, pérdida de datos y daños a la reputación de una aplicación al comprometer su seguridad. Es un problema frecuente debido a la manipulación de consultas SQL mediante entradas de usuario no validadas.
P) ¿Cómo se puede evitar la Inyección SQL en PHP?
A) La forma más eficaz de evitar la Inyección SQL es utilizar Sentencias Preparadas y Consultas Parametrizadas. PHP las soporta a través de las extensiones PDO (PHP Data Objects) y MySQLi, asegurando que la entrada del usuario sea tratada estrictamente como datos, no como código ejecutable.
P) ¿Existen otros métodos para evitar la Inyección SQL además de las Sentencias Preparadas?
R) Sí, la validación y el saneamiento de las entradas son cruciales. Garantizan que las entradas del usuario cumplen unos criterios específicos antes de ser procesadas en las consultas SQL. Además, escapar las entradas del usuario puede ser útil.
Start Growing with Cloudways Today.
Our Clients Love us because we never compromise on these
Inshal Ali
Inshal es Content Marketer en Cloudways. Con formación en informática, habilidad para los contenidos y mucha creatividad, ayuda a las empresas a alcanzar el cielo e ir más allá a través de contenidos que hablan el idioma de sus clientes. Aparte del trabajo, le verás sobre todo en algún juego en línea o en un campo de fútbol.