FlawOpen

flawopen.com/SQL Injection/¿Basta con escapar?

¿Escapar comillas evita SQL Injection?

CWE-89: SQL InjectionReference page
Respuesta breve

Por lo general, no. Una función de escape depende de la base de datos, el juego de caracteres de la conexión, el modo SQL y el contexto exacto de las comillas. Las consultas parametrizadas mantienen los valores fuera de la sintaxis SQL mediante la API del controlador. Usa parámetros para los valores; para identificadores dinámicos que no admiten parámetros, elige una opción de una lista permitida por la aplicación.

Por qué el escape es frágil en la práctica

El juego de caracteres de la conexión afecta al escape

El escape no es una sustitución de texto independiente del contexto. MySQL documenta que mysql_real_escape_string() usa el juego de caracteres de la conexión y que SET NAMES no actualiza el estado de la biblioteca cliente que utiliza esa función. Una discrepancia puede invalidar las suposiciones sobre el texto escapado. Prefiere APIs parametrizadas; si el código heredado aún necesita escape, usa la API del controlador con el juego de caracteres configurado mediante su función compatible y gestiona los errores.

Una llamada omitida rompe la defensa

El escape debe aplicarse correctamente en cada punto de interpolación, con el controlador, juego de caracteres, modo SQL y contexto de literal adecuados. Las APIs parametrizadas hacen explícita la separación entre valor y dato en la llamada y evitan construir manualmente una cadena entre comillas.

Escapar comillas no cubre todos los contextos SQL

Escapar comillas solo trata caracteres dentro de un literal de cadena concreto. No construye de forma segura una columna, tabla, palabra clave o dirección de ordenación, ni protege entradas en expresiones numéricas sin comillas. Vincula valores y asigna la estructura dinámica a opciones fijas controladas por la aplicación.

VULNERABLE
// La entrada del usuario se interpola en la sintaxis SQL
query = f"SELECT id FROM users WHERE name = '{name}'"
cursor.execute(query)
HARDENED
// El controlador vincula name como valor
cursor.execute(
    "SELECT id FROM users WHERE name = ?",
    (name,),
)

Qué cambia con la vinculación de parámetros

Una consulta parametrizada pasa la estructura SQL y los valores como entradas separadas mediante la API de la base de datos. Los controladores pueden usar sentencias preparadas nativas u otra implementación segura; no presupongas una secuencia concreta del protocolo. La propiedad de seguridad es que el valor se trate como dato y no se vuelva a analizar como sintaxis SQL. En Python DB-API, usa el marcador del controlador y pasa los valores por separado; no construyas la consulta con formato de cadenas.

Lista de verificación de ingeniería

Preguntas frecuentes

¿El escape puede seguir siendo la herramienta adecuada?

Para identificadores o fragmentos SQL que no admiten parámetros, usa solo una API de cita compatible con el controlador y una lista permitida fija de la aplicación. No uses escape genérico para valores arbitrarios.

Si se mantiene la función de escape del controlador, ¿es segura?

Una función mantenida puede ayudar en su contexto documentado, pero depende de la base de datos, la configuración de conexión, el contexto de cita y el uso correcto en cada punto. Las consultas parametrizadas son la opción predeterminada más segura para valores.

Referencias

Véase también Inyección SQL (CWE-89): cómo funciona y cómo evitarla en cada lenguaje — flawopen.com ¿Basta con usar un ORM para prevenir la inyección SQL? ¿Knex.js es seguro frente a SQL Injection? MyBatis ${} vs #{}: evitar SQL Injection MySQLi vs PDO: prepared statements seguros ¿NHibernate protege frente a SQL Injection? Inyección NoSQL en MongoDB: filtros seguros