¿Cómo evitar una inyeccion SQL en PHP?

10

En este tutorial os contamos cómo evitar uno de los ataques mas frecuentes de los hackers: La inyección SQL.

Os vamos a mostrar 3 scripts de PHP que nos van a permitir conocer la forma en que podemos evitar una inyección SQL por parte de posibles atacantes.

Para ello revisemos primero este primer script y analicemos

<?php
 
$query = "SELECT *
          FROM   users
          WHERE  name = '{$_GET['name']}'";
          
?>

Este script puede ser fácilmente vulnerable porque directamente agrega el valor de la variable ‘name’ a la sentencia SQL. Como puede ver permite para que el atacante agregue lo que desee y pueda comprometer nuestros datos.

Otra opción, aunque no muy recomendable sería la que se muestra debajo. En esta opción primero se verifica que los caracteres de la variable ‘name’ sean numéricos, luego se escapan los caracteres especiales haciendo uso de la función de php llamada mysql_real_escape_string. Por último se construye la sentencia SQL haciendo uso de los datos ya tratados previamente.

<?php

// Inicializar arreglos para datos filtrados y escapados, respectivamente.
$clean = array();
$sql = array();
 
// Filtra el nombre. Solo caracteres alfabéticos.
if (ctype_alpha($_GET['name'])) {
    $clean['name'] = $_GET['name'];
} else {
    // El nombre es inválido. Se debe tomar una acción aquí.
}
 
// Escapar el nombre
$sql['name'] = mysql_real_escape_string($clean['name']); 
 
// Construir la consulta
$query = "SELECT *
          FROM   users
          WHERE  name = '{$sql['name']}'";
 
?>

La última opción –la preferida– se muestra debajo. En ella simplemente se transfiere a PHP y MySQL la tarea de verificar la sentencia SQL. Se hace uso del método prepare de la clase PDO para preparar la sentencia y de execute para ejecutarla. Notemos el uso de los dos puntos antes de ‘name’ en la preparación de la sentencia y en la ejecución de la misma. Estos son requisitos que no podemos omitir.

<?php
 
// Creando el formato de la consulta
$query = $db->prepare('SELECT *
                       FROM   users
                       WHERE  name = :name');
 
// Indicando los datos
$query->execute(array(':name' => $clean['name']));
 
?>
Comparte este post.
Artículos Recomendados Para Tí:

10 Comments

    • Hola German, la segunda opción no es recomendable porque nosotros mismos debemos agregar a mano cada una de los filtros a los datos obtenidos mediante GET. Si olvidamos filtros podríamos hacer vulnerable el script poniendo en riesgo la seguridad de nuestra aplicación. La tercera opción, en cambio, es menos engorrosa y deja todo el trabajo pesado a PHP.

      Gracias por escribirnos.

  1. Les ayudo con la que yo utilizo que me va de lujo…

    function securitymax($valores) {
    $_Cadena = htmlspecialchars(trim(addslashes(stripslashes(strip_tags($valores)))));
    $_Cadena = str_replace(chr(160),”,$valores);
    return mysql_real_escape_string($valores);
    }

    $minurl = $_GET[‘id2’];
    $minurla = str_replace(“‘”, “”, $minurl);
    $minurlb = str_replace(“;”, “”, $minurla);
    $minurlokc = str_replace(“\””, “”, $minurlb);
    $minurlok = securitymax($minurlokc);

    Donde “$newurlok” es la variable completamente saneada

      • Una consulta
        en
        $_Cadena = htmlspecialchars(trim(addslashes(stripslashes(strip_tags($valores)))));
        $_Cadena = str_replace(chr(160),”,$valores);

        no seria
        $_Cadena = htmlspecialchars(trim(addslashes(stripslashes(strip_tags($valores)))));
        $_Cadena = str_replace(chr(160),”,$_Cadena);

  2. a mi me queda una duda… Con las consultas preparadas de PDO, se debe utilizar addslashes y mysql_real_escape_string de todas formas? o solo con preparar la consulta, y hacer los bind a la consulta ya esta la seguridad?
    Muchísimas gracias.

  3. alguien podria ayudarme a cambiar este codigo mysqli a PDO

    escape_string($_POST[‘datepicker’]);
    $new_date = date(‘Y-m-d’,strtotime($date));
    $equipo = $mysqli->escape_string( trim($_POST[‘bien’]));
    $marca = $mysqli->escape_string( trim($_POST[‘marca’]));
    $modelo = $mysqli->escape_string( trim($_POST[‘modelo’]));
    $serie = $mysqli->escape_string( trim($_POST[‘serie’]));

    $sql = “INSERT INTO equipo_inf(fecha_registro, nomb_equipo, marca_equi, modelo_equi, serie_equi)
    VALUES (‘$new_date’,’$equipo’, ‘$marca’, ‘$modelo’, ‘$serie’)”;

    if($mysqli->query($sql)){
    header(‘Location: registronuevo.php’);
    }else die($mysqli->error);

    ?>