Prevenir la inyección de SQL en PHP

Subodh Poudel 30 enero 2023
  1. Utilice las declaraciones preparadas y el PDO para evitar la inyección de SQL en PHP
  2. Utilice las declaraciones preparadas con la consulta parametrizada para evitar la inyección de SQL en PHP
  3. Establezca el atributo PDO::ATTR_EMULATE_PREPARES en false para evitar la inyección de SQL
Prevenir la inyección de SQL en PHP

Introduciremos un método para evitar la inyección de SQL en PHP utilizando las declaraciones preparadas y los objetos de datos PHP (PDO). Usamos PDO para establecer la comunicación de la base de datos en este método. Este método envía los datos y la consulta por separado al servidor de la base de datos, lo que evita la mezcla de los datos y el servidor.

Introduciremos un método para evitar la inyección de SQL en PHP utilizando las declaraciones preparadas y la consulta parametrizada. Usamos mysqli para establecer la comunicación de la base de datos en este método. Este método tiene un mecanismo de trabajo similar al del primer método. El punto de contraste son solo las funciones mysqli que usamos para evitar la inyección de SQL.

Le mostraremos un ejemplo de cómo estar a salvo de la inyección de SQL mientras usa el PDO en PHP configurando la emulación de declaraciones preparadas en false.

Utilice las declaraciones preparadas y el PDO para evitar la inyección de SQL en PHP

Podemos usar la declaración preparada junto con el PDO para evitar la inyección de SQL en PHP. La inyección de SQL ocurre cuando hay una mezcla de la consulta y los datos mientras se envían a la base de datos. En este método, no especificamos el valor exacto de los datos en la declaración SQL. En su lugar, usamos los marcadores de posición. Debido a esto, las sentencias SQL parametrizadas se envían al servidor como primera solicitud. Usamos la función prestop() para lograr esto. Vinculamos el valor exacto del parámetro en la segunda solicitud al servidor de la base de datos. Usamos la función bindValue() para este propósito. De esta forma, enviamos el programa en la primera solicitud y los datos en la segunda solicitud. Si solicitamos los datos junto con los códigos SQL, el usuario puede alterar el programa y escribir códigos maliciosos. Por lo tanto, evita que los códigos SQL maliciosos se inyecten en el servidor.

Por ejemplo, una tabla users contiene los siguientes campos y datos.

+----+-----------+----------+------------+
| id | firstname | lastname | dob        |
+----+-----------+----------+------------+
|  1 | bruce     |  rose    | 1998-02-13 |
|  2 | jeff      |  james   | 2000-03-30 |
+----+-----------+----------+------------+

Crea una variable $firstname y le asigna el nombre bruce. Crea una variable $sql y escribe una consulta SELECT * FROM users WHERE firstname =:fname; en eso.

No escriba el valor exacto de los datos para firstname. En su lugar, utilice el parámetro :fname. Utilice la variable $pdo para llamar a la función prepare() en la variable de consulta. Reemplace el valor de :fname con la variable firstname. Ejecute la instrucción con la función execute(). Verifique el resultado con la función fetch() si las credenciales coinciden con la base de datos. Si es así, muestre el id, firstname, y el lastname de la fila seleccionada.

El siguiente ejemplo demuestra el uso de una declaración preparada. Almacena el valor del campo firstname en una variable para verificar si la credencial coincide. Si la variable hubiera contenido algún código malicioso en su lugar, mostraría el mensaje Credentials do no match. Esto se debe a que la función prepared() toma solo la consulta parametrizada y no permite los datos exactos. La variable $pdo contiene el objeto de la conexión a la base de datos.

Código de ejemplo:

# php 7.*
<?php
$firstname = "bruce";
$sql = "SELECT * FROM users WHERE firstname =:fname ;";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(":fname", $firstname);
$stmt->execute();
if(!$result = $stmt->fetch(PDO::FETCH_OBJ)){
    echo "Credentials do no match";
} else {
    echo"Id: ".$result->id. " Name: ".$result->firstname." ".$result->lastname;
}
?>

Producción :

Id: 1 Name: bruce rose

Utilice las declaraciones preparadas con la consulta parametrizada para evitar la inyección de SQL en PHP

Podemos usar la declaración preparada junto con la consulta parametrizada para evitar la inyección de SQL en PHP. Usamos el objeto de la función mysqli() para crear una conexión a la base de datos. En este método, usamos un símbolo de interrogación ? como marcadores de posición de los datos. Usamos la función prepare() como el método anterior. Usamos la función bind_param() para vincular los datos reales en el marcador de posición. Este método sigue un mecanismo de trabajo similar al método anterior.

Por ejemplo, establezca una conexión a la base de datos creando un objeto de la función mysqli() y asígnelo a una variable $conn. Asignar con el nombre jeff a una variable $firstname. Cree una variable $sql y escriba una consulta SELECT * FROM users WHERE first name =?;. Utilice la variable $conn para llamar a la función prepare() en la variable de consulta. Reemplazar el marcador de posición ? con la variable $firstname. Ejecute la instrucción con la función execute(). Llame a la función get_result() para almacenar el resultado en la variable $result. Compruebe si la fila existe con la propiedad num_rows y devuelva el mensaje No Rows con la función exit() si la condición falla. Llame al método fetch_assoc() y guárdelo en la variable $row en un bucle while. Muestra el id, firstname, y el lastname de la fila seleccionada.

Código de ejemplo:

#php 7.x
<?php
$conn = new mysqli($host, $user, $pwd, $dbName);
$firstname = "jeff";
$sql = "SELECT * FROM users WHERE firstname = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("s", $firstname);
$stmt->execute();
$result = $stmt->get_result();
if($result->num_rows === 0) exit('No rows');
    while($row = $result->fetch_assoc()) {
    echo"Id: ".$row['id']. " Name: ".$row['firstname']." ".$row['lastname'];
}

Producción :

Id: 2 Name: jeff james

Establezca el atributo PDO::ATTR_EMULATE_PREPARES en false para evitar la inyección de SQL

El uso de declaraciones preparadas en PDO puede no ser suficiente para evitar la inyección de SQL si no configuramos los atributos de PDO correctamente. Debemos establecer el atributo PDO::ATTR_EMULATE_PREPARES en false para evitar la inyección. Si establecemos el atributo en true, el PDO solo emulará las declaraciones preparadas en lugar de utilizarlas. Por lo tanto, el sistema será vulnerable a la inyección de SQL.

Por ejemplo, cree una conexión PDO a la base de datos en una variable $pdo. Utilice la variable para llamar a la función setAttribute(). Establezca el atributo PDO::ATTR_EMULATE_PREPARES en falso.

Ejemplo de código:

#php 7.x
<?php
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
?>
Subodh Poudel avatar Subodh Poudel avatar

Subodh is a proactive software engineer, specialized in fintech industry and a writer who loves to express his software development learnings and set of skills through blogs and articles.

LinkedIn