FlawOpen

flawopen.com/SQL Injection en PHP/mysqli vs PDO

MySQLi vs PDO: prepared statements seguros

Página de referencia
Respuesta breve

Una prepared statement mantiene fijas las instrucciones SQL y envía los valores por separado, como rellenar casillas etiquetadas. PDO y MySQLi permiten hacerlo. La seguridad depende de enlazar bien los valores, no del nombre de la biblioteca.

La misma consulta preparada con ambas API

INSEGURO — SQL con datos de la solicitud
$userId = $_GET['id'];
$sql = "SELECT id, email FROM users WHERE id = " . $userId;

// Both calls execute the already-built SQL string:
$rows = $mysqli->query($sql);
$rows = $pdo->query($sql);
SEGURO — vincula valores en ambas API
// PDO
$stmt = $pdo->prepare(
    "SELECT id, email FROM users WHERE id = :id"
);
$stmt->execute(["id" => $userId]);

// MySQLi
$stmt = $mysqli->prepare(
    "SELECT id, email FROM users WHERE id = ?"
);
$stmt->bind_param("i", $userId);
$stmt->execute();

La portabilidad de bases de datos es la principal diferencia de PDO

La portabilidad de bases de datos es la principal diferencia de PDO

PDO ofrece una interfaz común para varios drivers; MySQLi se limita a MySQL y MariaDB. PDO no vuelve portable el SQL por sí mismo: los dialectos, drivers y funciones siguen variando.

Los estilos de placeholder son distintos

PDO admite placeholders con nombre, como :id, o posicionales ?, según el driver; no mezcles estilos. MySQLi usa ?. Ambos enlazan valores, no nombres de tablas o columnas, palabras clave ni ordenaciones.

El modo de preparación de PDO depende del driver

Los drivers PDO pueden usar preparaciones nativas o emuladas. En MySQL, PDO::ATTR_EMULATE_PREPARES controla la emulación cuando está disponible; algunos drivers emulan o recurren a ella si no pueden preparar de forma nativa. Sigue la documentación del driver. Esta opción no protege SQL interpolado: fija el texto y enlaza valores en cualquier modo.

Reglas contra SQL injection para ambas bibliotecas

Usa prepare() y enlaza cada valor no confiable. Mantén fija la sintaxis SQL; elige identificadores dinámicos de un mapa estricto del servidor o usa variantes finitas. Una prepared statement no autoriza el acceso a filas: limita la consulta al usuario autenticado cuando corresponda. En LIKE, enlazar evita la inyección SQL, pero % y _ siguen siendo comodines salvo que se escapen para buscar literalmente.

Elegir entre PDO y MySQLi

Preguntas frecuentes

¿Son más seguros los placeholders con nombre de PDO que los ? de MySQLi?

No. Ambos enlazan valores de forma segura si la consulta se prepara y los valores se vinculan. Los nombres pueden facilitar la lectura, pero no enlazan identificadores ni reemplazan la autorización.

¿Debo desactivar siempre las preparaciones emuladas de PDO?

No como regla general. El soporte y el fallback varían por driver. Consulta su documentación y los requisitos de la aplicación. Mantén fija la estructura SQL y pasa valores como parámetros en cualquier modo.

¿Una prepared statement puede enlazar un nombre de tabla o columna?

No. Los parámetros representan valores, no identificadores ni palabras clave SQL. Mapea la elección del cliente a fragmentos confiables y finitos en el servidor.

Referencias

Véase también Inyección SQL (CWE-89): cómo funciona y cómo evitarla en cada lenguaje — flawopen.com ¿NHibernate protege frente a SQL Injection? Inyección NoSQL en MongoDB: filtros seguros SQL Injection en IDs numéricos: ¿riesgo? ¿Qué es una consulta parametrizada? ¿Prisma $queryRaw es seguro frente a SQL Injection? ¿Es segura la interpolación en where() de Rails?