Funcionamiento de ->real_escape_string

publicado por: Anonymous

Tengo un login, que cuando meto usuario y contraseña en un formulario y apreto “entrar” y tengo establecida la conexión con la base de datos, utiliza la siguiente linea de código:

$pass = $mysqli->real_escape_string($_POST['txtpass']);

Estoy informándome por internet, pero no entiendo el ->real_escape_string

¿que significa? ¿cómo me protege de SQL-INJECTION?

Les dejo el trozo de código completo

 <?php
if(isset($_POST['txtpass'])) 
{
    session_start();
    //variable de conexion: recibe dirección del host , usuario, contraseña y el nombre base de datos
    $mysqli = new mysqli("localhost", "root", "", "bdpersona") or die ("Error de conexion porque: ".$mysqli->connect_errno);
    // comprobar la conexión 
    if (mysqli_connect_errno()) 
    {
        printf("Falló la conexión: %sn", mysqli_connect_error());
        exit();
    }

    $login = $mysqli->real_escape_string($_POST['txtlogin']);   
    $pass = $mysqli->real_escape_string($_POST['txtpass']);

    $resultado = $mysqli->query("SELECT * FROM tbusuario where login='$login' and pass='$pass' and activo!=0");
    $valida=$resultado->num_rows;
    if($valida != 0)
    {
        $datosUsu = $resultado->fetch_row();
        $_SESSION['nombreusu'] = $datosUsu[3];
        $_SESSION['perfil'] = $datosUsu[4];             
        echo "<META HTTP-EQUIV='Refresh' CONTENT='0; URL=listar.php'>";
    }
    else
    {
        echo 
        "<script> 
            var textnode = document.createTextNode('Usuario ó Password Incorrecto');
            document.getElementById('msg').appendChild(textnode);
        </script>";

    }   
}

?>

Gracias.

solución

En muchos casos real_escape_string no te protege de la Inyección SQL, porque hay valores de sustitución que esta función no escapa (ver esta pregunta y su respuesta).

Si te quieres proteger de la Inyección SQL, usa consultas preparadas.

Es muy simple hacerlo. Lee los comentarios en el código, donde voy explicando lo que he hecho:

 $login = $_POST['txtlogin'];  
 $pass  = $_POST['txtpass'];
/*
  * 1. Usamos prepare en lugar de query
  * 2. Cambiamos las variables por marcadores de posición ?
  *    Este es el núcleo del riesgo de inyección, porque las variables
  *    pueden ser concatenadas con código malicioso que se ejecutaría
  *    Nótese que he puesto las columnas explícitamente en el SELECT
  *    asumiendo que las mismas se llaman nombreusu y perfil ...
*/

$sql = "SELECT nombreusu, perfil FROM  registros where login=? and pass=? and activo!=0";
$stmt = $mysqli->prepare($sql);

/*
  * 3. Pasar parámetros separados  de la instrucción SQL
  *    Así se neutraliza la Inyección
  *    Para ello se usa un método llamado bind_param
  *    Las dos "ss" indican que hay dos columnas en la instrucción SQL de más arriba
  *    y que las mismas son del tipo String, por eso la s. 
  *    Si fueran números sería un i
  *    Luego se pasa el valor de esas variables, las cuales almacenamos desde el POST
  *    Es decir, tiene que haber tantos tipos de datos (en este caso "ss") 
  *    como columnas con marcadores de posición, 
  *    si por ejemplo la 1ª fuera String y la 2ª fuera número, entonces sería "si"
  *    y también tantas variables como columnas (dos variables en este caso)
  *    y tienen que ir en el orden en que aparecen en la consulta
*/
$stmt->bind_param("ss", $login,$pass);
$stmt->execute();

/*
  * 4. Usamos bind_result para almacenar en variables cada columna del SELECT
  *    Esto hay que hacerlo siempre ANTES de fetch...
  *    En bind_result debe habar tantas variables como columnas tenga el SELECT
  *    Nótese que store_result y num_rows ya no son necesarios, porque
  *    dado que fetch devolverá NULL si no hay datos, podemos aprovechar
  *    ese resultado para evaluar, optimizando así el código
*/

 $stmt->bind_result($nombreusu, $perfil);

if ($stmt->fetch())
{
    /* Aquí usaremos las variables de bind_result*/

    $_SESSION['nombreusu'] = $nombreusu;
    $_SESSION['perfil'] = $perfil;             
    echo "<META HTTP-EQUIV='Refresh' CONTENT='0; URL=listar.php'>";
}
else
{
    echo 
    "<script> 
        var textnode = document.createTextNode('Usuario ó Password Incorrecto');
        document.getElementById('msg').appendChild(textnode);
    </script>";

} 

P. D.: Dado que al parecer sólo se trata de una validación, he cambiado el SELECT * por un SELECT COUNT(*) ..., ya que es lo más eficaz para estos fines.

Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *