Eliminando Vulnerabilidades y Proteger tu Sitio de Inyección SQL
64
Views

La inyección SQL es una de las vulnerabilidades más peligrosas que quita el sueño a los desarrolladores. Aprende a combatirla para proteger tu sitio web.

Lanzas un sitio, lo llenas de contenido, inicias una campaña publicitaria: el tráfico crece de manera constante, los usuarios comentan y comparten artículos activamente. Todo va bien hasta que un día, sin previo aviso, descubres que no queda ni un solo artículo en el sitio. Revisas los registros de consultas y ves que alguien ejecutó un comando DROP…

¿Qué es una Inyección SQL?

Concepto de Inyección SQL
Concepto de Inyección SQL

La inyección SQL es un intento de modificar una consulta a la base de datos. Se puede introducir a través de un formulario o un enlace que transmite parámetros mediante el método GET. Imagina que en tu sitio hay un formulario de registro donde el usuario ingresa un nombre de usuario y una contraseña.

<form action='reg.php' method='post'>
  <input type='text' name='login' placeholder='Nombre de usuario' required><br>
  <input type='password' name='password' placeholder='Contraseña' required><br>
  <input type='submit' value='Registrarse'>
</form>

Estos datos se envían al servidor y se insertan en una consulta como esta:

$query = "INSERT INTO userlist (" . $keys . ") VALUES (" . $values . ")";

En la variable $keys se almacenan las claves del superglobal $_POST, y en $values los valores:

$keys = "";
$values = "";
$first = 1;
foreach ($_POST as $key => $value) {
    if ($first == 0) { // Añade una coma antes de cada elemento, excepto el primero
        $keys .= ",";
        $values .= ",";
    }
    $keys .= $key;
    $values .= "'" . $value . "'";
    $first = 0;
}

Esto es conveniente si el formulario tiene muchos campos, pero introduce una vulnerabilidad: si un usuario desea ejecutar una inyección SQL, puede simplemente crear un nuevo campo en el formulario con el nombre que desee e ingresar cualquier valor. Por ejemplo, puede crear un campo admin y asignarle el valor 1.

<br><input type='number' name='admin' value='1' required><b>

Si el sitio no está bien protegido, el hacker puede realizar muchos intentos, pero eventualmente podría obtener acceso con privilegios de administrador.

Cómo Proteger tu Sitio de la Inyección SQL

Primero, recuerda que no existen sistemas completamente seguros, por lo que debes buscar constantemente vulnerabilidades que puedan afectar tu sitio.

1. Utiliza listas blancas

En el ejemplo anterior, nos habría salvado usar una lista blanca, especificando las claves y valores permitidos.

$keys = "";
$values = "";
$first = 1;
$allowed = array("login", "password", "email", "nickname");
foreach ($_POST as $key => $value) {
    if (in_array($key, $allowed)) {
        if ($first == 0) {
            $keys .= ",";
            $values .= ",";
        }
        $keys .= $key;
        $values .= "'" . $value . "'";
        $first = 0;
    }
}

Ahora, solo las claves y valores que están en la lista blanca $allowed se incluirán en las variables $keys y $values.

2. No utilices el método GET en formularios

Transmitir variables de esta manera es muy peligroso, ya que quedan visibles para los usuarios. Si la información es importante, es mejor usar POST. De un enlace, un atacante puede no solo conocer los nombres de las variables, sino también los valores que deberían tener, permitiéndole elegir la variable óptima para la inyección.

No recomendamos usar variables directamente del superglobal; es mejor asignarlas a otra variable después de validarlas.

3. Procesa las variables

Procura escapar comillas, reemplazar caracteres especiales, eliminar espacios innecesarios, etc. Veamos qué pasaría si no lo haces:

Usa funciones como trim (elimina espacios innecesarios), htmlspecialchars (reemplaza corchetes angulares y otros caracteres especiales), addslashes (escapa comillas y caracteres especiales), entre otras.

En el formulario de registro, un atacante podría usar comillas y comas para agregar una nueva clave y valor. Por ejemplo, al ingresar algo como pass', 'algo en el campo, añadiría información adicional que no pasa la lista blanca.

También puedes verificar los tipos de variables: número, cadena, archivo, etc.

4. Verifica de dónde vienen los datos

No basta con procesar los datos, es necesario saber de dónde provienen. Puedes rastrear el origen de varias maneras:

  • Verificarlo en $_SERVER['HTTP_REFERER'].
  • Crear un campo oculto en el formulario.
  • Especificar el nombre del formulario.
  • Especificar el nombre del botón de envío, etc.

Claro, esto solo es un pequeño extra en la protección, pero ayuda a descartar a atacantes inexpertos que abandonarán después de algunos intentos.

5. Usa PDO

Con PDO (PHP Data Objects) y placeholders, puedes reducir significativamente el riesgo de inyección, ya que los datos y la consulta se envían por separado. Primero se conecta a la base de datos, luego se prepara la consulta, se especifican las variables por separado y, finalmente, se ejecuta la consulta. Así se ve:

$db = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
$stmt = $db->prepare("SELECT * FROM articles WHERE id=:id");
$stmt->bindParam(':id', $id);
$stmt->execute();

Los datos se envían como variables. Si alguien coloca una comilla adicional en la variable, el servidor no la considerará parte de la consulta. Por lo tanto, cualquier intento de alterar la consulta mediante la variable no funcionará.

Este método es probablemente el más efectivo, así que cambia a PDO lo antes posible. Sin embargo, su uso no significa que las otras medidas de seguridad no sean necesarias. Cuantos más mecanismos de protección implementes, más segura estará la información.

Frecuentemente, los autodidactas que estudian de manera superficial omiten estas verificaciones. Pueden resolver problemas, pero rara vez piensan en eliminar vulnerabilidades.

Protección Adicional del Sitio Contra Ataques

Además de proteger las consultas y variables, es crucial eliminar todas las posibles brechas que puedan llevar a una filtración de información o acceso no autorizado a los derechos de administrador.

1. Prohibir el acceso directo a archivos de servicio

Todos los archivos en un sitio web pueden abrirse o descargarse si se conoce su dirección. Por ejemplo, se puede intentar descargar el archivo header.php para buscar vulnerabilidades.

Es mejor mover todos los archivos incluidos en una carpeta separada y prohibir el acceso directo a ella. Puedes crear una carpeta llamada includes y colocar allí:

  • Bloques separados del sitio;
  • Bibliotecas de funciones personalizadas;
  • Archivo de conexión a la base de datos;
  • Controladores de formularios, etc.

Para esto, crea un archivo .htaccess en esa carpeta y añade la siguiente línea:

deny from all

El acceso directo será bloqueado, pero aún se podrán incluir estos archivos mediante PHP.

2. No publiques tu código en foros

A veces necesitamos ayuda de colegas, por lo que publicamos fragmentos de nuestro código en foros o Stackoverflow. Hazlo solo en casos extremos y asegúrate de que nadie pueda identificar tu sitio web.

Nada debe indicar la temática del sitio, su dirección, el hosting en el que se encuentra, etc. Cuanta más información divulgas voluntariamente, mayor es el riesgo de ser hackeado.

3. Verifica el código copiado

Siempre revisa el código que copias, ya que podría contener un exploit que perjudique tu sitio o permita al autor del código acceder a él. Trata de leer lo que estás pegando. Incluso una sola línea puede ser suficiente para crear una brecha en tu seguridad.

Idealmente, reescribe el código manualmente; así notarás cualquier comando sospechoso.

4. Desactiva la visualización de errores

Mostrar errores es muy útil durante el desarrollo, pero si el sitio ya está en línea, es mejor desactivar las notificaciones de errores. Un atacante podría ver los problemas del sitio e intentar explotar esas vulnerabilidades.

Puedes desactivar la visualización de errores en el archivo .htaccess añadiendo las siguientes líneas:

php_flag display_errors off
php_value error_reporting 0

Además, elimina cualquier salida de errores que hayas incluido en tu código.

5. Restringe los permisos del usuario de la base de datos

Normalmente, para conectar a la base de datos se crea una cuenta con todos los permisos para aprovechar todas las capacidades de SQL. Sin embargo, es mejor restringirlos. Entra a phpmyadmin, añade un nuevo usuario y dale solo algunos permisos.

Marca solo el permiso “Datos”. Esto permitirá operar con datos existentes, pero no crear nuevas tablas ni eliminar las antiguas. Así te protegerás de ataques con comandos como DROP, que podrían eliminar todas las entradas del sitio.

Si el administrador de tu sitio necesita privilegios para modificar la estructura regularmente, crea un usuario separado para usar en la administración. Sin embargo, existe el riesgo de que alguien obtenga acceso a la administración. Limita el número máximo de conexiones y solicitudes.

También es mejor poner una contraseña a root para evitar que un atacante se conecte con este usuario.

6. Instala la última versión del lenguaje

Las versiones antiguas de cualquier lenguaje suelen ser menos funcionales y tienen muchas vulnerabilidades. Las brechas críticas se conocen desde hace años, por lo que los hackers las usan para atacar sitios.

Sí, las actualizaciones también pueden tener errores, pero no tan peligrosos. Además, nadie los conocerá si ha pasado poco tiempo desde su lanzamiento.

7. Usa una contraseña segura

Es básico, pero una contraseña simple puede ser descifrada en segundos, especialmente si contiene datos personales:

  • Fecha de nacimiento;
  • Nombre de una mascota;
  • Aniversario de boda;
  • Apellido de soltera de la madre, etc.
Variantes de contraseñas poco seguras
No hagas esto para utilizarlo como contraseña

Es común que esta información se publique libremente.

Conclusión

No existen sistemas completamente seguros; solo puedes reducir la probabilidad de un ataque. Para ello, debes ser un poco hacker:

  • Introducir inyecciones;
  • Cambiar tipos de datos;
  • Añadir comillas y caracteres de escape en los campos;
  • Intentar subir un archivo .php con código malicioso, etc.

Intenta hackear tu propio sitio para descubrir sus vulnerabilidades. Hazlo antes de que alguien más lo haga.

Categorías:
Trucos

Todos los Comentarios

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *