¿Qué tan seguro es este código php contra la inyección de SQL?

2

El código que se proporciona a continuación es una parte de un código de script de inicio de sesión simple.

if (isset ($_POST['login'])) { 
                $username = $_POST['username']; 
                $password = $_POST['password'];
                $password_hash = sha1($password);

                $query = "SELECT id,username FROM users WHERE username = '".mysqli_real_escape_string($link,$username)."' AND password ='".$password_hash."'";

Estas son algunas de mis dudas:

  1. ¿El código anterior es vulnerable a algún tipo (error, ciego, unión basada) de inyección SQL?
  2. Si el código anterior es vulnerable a los ataques de inyección de SQL, ¿cómo y por qué el atacante puede lanzar el ataque?
  3. Si el código anterior es seguro, ¿por qué la gente sigue buscando declaraciones preparadas, etc.?
pregunta ysj 26.01.2013 - 16:58
fuente

2 respuestas

15
  

¿El código anterior es vulnerable a cualquier tipo (error, ciego, unión basada) de inyección SQL?

No, pero solo porque sha1() sucede por suerte para producir resultados que nunca contienen metacaracteres SQL.

Su código de creación de consultas no debería tener que conocer los detalles de la implementación. También debería estar escapando de $password_hash , para que la línea de código funcione por sí sola y se pueda verificar como correcta y segura sin tener que mirar el contexto más amplio. De lo contrario, cuando cambie la forma en que se calcula ese $password_hash (por ejemplo, para almacenar un hash salado más seguro), es posible que haya creado una vulnerabilidad en ese código de consulta. Crear un acoplamiento innecesario entre bits de código dispares, potencialmente en diferentes archivos, es en general una mala idea.

  

Si el código anterior es seguro, ¿por qué la gente sigue buscando declaraciones preparadas, etc.?

Porque las declaraciones preparadas suelen ser más fáciles de leer, comprender y verificar; es más difícil omitir accidentalmente un escape. Comparar:

$query = "SELECT id,username FROM users WHERE username = '"
         .mysqli_real_escape_string($link, $username)
         ."' AND password ='"
         .mysqli_real_escape_string($link, $password_hash)
         ."'";

con:

$query = $mysqli->prepare('SELECT id,username FROM users WHERE username=? AND password=?')
$query->bind_param('ss', $username, $password_hash);

Aunque no soy un gran fanático de la marca particular de mysqli de consultas parametrizadas (especialmente vinculadas a variables en lugar de valores), esta última todavía me parece más simple y más mantenible.

    
respondido por el bobince 28.01.2013 - 18:44
fuente
8

Estás usando SHA-1 para el hash de tu contraseña sin sal. Esto es malo mal malo Consulte ¿Cómo hacer hash de forma segura las contraseñas? para una mejor manera de hacer hash de sus contraseñas .

En segundo lugar, consulte Cómo evitar la inyección de SQL en PHP para una explicación de mysqli_real_escape_string vs declaraciones preparadas.

Puede que te olvides de escapar de las cadenas. El uso de declaraciones preparadas para toda su aplicación hace que sea mucho menos probable que sea vulnerable a los ataques de inyección de SQL.

Además, la sintaxis de la cadena de escape es sencillamente fea.

En tercer lugar, ¿por qué utiliza la cláusula WHERE para realizar la autenticación en lugar de recuperar el hash de nombre de usuario y contraseña de su base de datos y realizar una comparación?

    
respondido por el Ayrx 26.01.2013 - 17:00
fuente

Lea otras preguntas en las etiquetas