Con respecto a muchas respuestas útiles, espero agregar algo de valor a este hilo.
La inyección SQL es un ataque que se puede realizar a través de entradas de usuario (entradas que rellena un usuario y luego se utilizan dentro de las consultas). Los patrones de inyección SQL son una sintaxis de consulta correcta, mientras que podemos llamarla: consultas malas por razones malas, y suponemos que podría haber una persona mala que intenta obtener información secreta (sin pasar por el control de acceso) que afecta los tres principios de seguridad (confidencialidad , integridad y disponibilidad).
Ahora, nuestro objetivo es evitar las amenazas de seguridad, como los ataques de inyección SQL, la pregunta que se hace (cómo evitar un ataque de inyección SQL usando PHP), ser más realista, el filtrado de datos o la eliminación de datos de entrada es el caso cuando se usan datos de entrada del usuario dentro tal consulta, el uso de PHP o cualquier otro lenguaje de programación no es el caso, o según lo recomendado por más personas para usar tecnología moderna como la declaración preparada o cualquier otra herramienta que actualmente soporte la prevención de inyección SQL, ¿considera que estas herramientas ya no están disponibles? ¿Cómo protege su aplicación?
Mi enfoque contra la inyección SQL es: borrar los datos de entrada del usuario antes de enviarlos a la base de datos (antes de usarlos dentro de cualquier consulta).
Filtrado de datos para (convertir datos inseguros en datos seguros)
Tenga en cuenta que PDO y MySQLi no están disponibles. ¿Cómo puede asegurar su aplicación? ¿Me obligas a usarlos? ¿Qué pasa con otros lenguajes que no sean PHP? Prefiero proporcionar ideas generales, ya que puede usarse para un borde más amplio, no solo para un idioma específico.
- Usuario SQL (privilegio de usuario limitado): las operaciones SQL más comunes son (SELECCIONAR, ACTUALIZAR, INSERTAR), entonces, ¿por qué otorgar el privilegio ACTUALIZAR a un usuario que no lo requiere? Por ejemplo, las páginas de inicio de sesión y búsqueda solo usan SELECT, entonces, ¿por qué usar usuarios de DB en estas páginas con altos privilegios?
REGLA: no cree un usuario de base de datos para todos los privilegios. Para todas las operaciones SQL, puede crear su esquema como (deluser, selectuser, updateuser) como nombres de usuario para facilitar su uso.
Ver principio de mínimo privilegio .
Filtrado de datos: antes de generar cualquier consulta del usuario, debe validarse y filtrarse. Para los programadores, es importante definir algunas propiedades para cada variable de entrada del usuario:
tipo de datos, patrón de datos y longitud de datos . Un campo que es un número entre (x e y) debe validarse exactamente usando la regla exacta, y para un campo que es una cadena (texto): el caso es el patrón, por ejemplo, un nombre de usuario debe contener solo algunos caracteres, vamos a diga [a-zA-Z0-9_-.]. La longitud varía entre (x y n) donde x y n (enteros, x <= n).
Regla: crear filtros exactos y reglas de validación son las mejores prácticas para mí.
Use otras herramientas: Aquí, también estaré de acuerdo con usted en que una declaración preparada (consulta parametrizada) y procedimientos almacenados. Las desventajas aquí son que estas formas requieren habilidades avanzadas que no existen para la mayoría de los usuarios. La idea básica aquí es distinguir entre la consulta SQL y los datos que se utilizan en su interior. Ambos enfoques se pueden usar incluso con datos inseguros, porque los datos ingresados por el usuario aquí no agregan nada a la consulta original, como (any o x = x).
Para obtener más información, lea la hoja de trucos de prevención de inyección SQL de OWASP .
Ahora, si es un usuario avanzado, comience a usar esta defensa como desee, pero, para los principiantes, si no pueden implementar rápidamente un procedimiento almacenado y prepararon la declaración, es mejor filtrar los datos de entrada tanto como puedan.
Finalmente, consideremos que un usuario envía este texto a continuación en lugar de ingresar su nombre de usuario:
[1] UNION SELECT IF(SUBSTRING(Password,1,1)='2',BENCHMARK(100000,SHA1(1)),0) User,Password FROM mysql.user WHERE User = 'root'
Esta entrada puede verificarse temprano sin ninguna declaración preparada y procedimientos almacenados, pero para estar seguros, su uso comienza después del filtrado y validación de los datos del usuario.
El último punto es detectar comportamientos inesperados que requieren más esfuerzo y complejidad; No se recomienda para aplicaciones web normales.
El comportamiento inesperado en la entrada del usuario anterior es SELECT, UNION, IF, SUBSTRING, BENCHMARK, SHA y root. Una vez que se detectan estas palabras, puede evitar la entrada.
ACTUALIZACIÓN 1:
Un usuario comentó que esta publicación es inútil, ¡OK! Esto es lo que proporcionó OWASP.ORG :
Defensas primarias:
Opción # 1: El uso de sentencias preparadas (consultas parametrizadas)
Opción # 2: El uso de procedimientos almacenados
Opción # 3: Escapar toda la entrada proporcionada por el usuario
defensas adicionales:
También Hacer cumplir: Privilegio
también llevan a cabo: Blanco la lista de entradas de validación
Como ya sabrás, ¡reclamar un artículo debe estar respaldado por un argumento válido, al menos por una referencia! De lo contrario, se considera un ataque y un mal reclamo.
Actualización 2:
Del manual de PHP, PHP: Declaraciones preparadas - Manual :
Inyección de escape y SQL
El servidor escapará automáticamente de las variables enlazadas. El servidor inserta sus valores escapados en los lugares apropiados en la plantilla de declaración antes de la ejecución. Se debe proporcionar una pista al servidor para el tipo de variable enlazada, para crear una conversión adecuada. Consulte la función mysqli_stmt_bind_param () para obtener más información.
El escape automático de valores dentro del servidor a veces se considera una característica de seguridad para evitar la inyección de SQL. Se puede lograr el mismo grado de seguridad con declaraciones no preparadas si los valores de entrada se escapan correctamente.
Actualización 3:
Creé casos de prueba para saber cómo PDO y MySQLi envían la consulta al servidor MySQL cuando se usa una declaración preparada:
DOP:
$user = "''1''"; // Malicious keyword
$sql = 'SELECT * FROM awa_user WHERE userame =:username';
$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':username' => $user));
Registro de consultas:
189 Query SELECT * FROM awa_user WHERE userame ='\'\'1\'\''
189 Quit
MySQLi:
$stmt = $mysqli->prepare("SELECT * FROM awa_user WHERE username =?")) {
$stmt->bind_param("s", $user);
$user = "''1''";
$stmt->execute();
Registro de consultas:
188 Prepare SELECT * FROM awa_user WHERE username =?
188 Execute SELECT * FROM awa_user WHERE username ='\'\'1\'\''
188 Quit
Está claro que una declaración preparada también está escapando de los datos, nada más.
Como también se menciona en la declaración anterior,
El escape automático de valores dentro del servidor a veces se considera una característica de seguridad para evitar la inyección de SQL. Se puede lograr el mismo grado de seguridad con declaraciones no preparadas, si los valores de entrada se escapan correctamente
Por lo tanto, esto prueba que la validación de datos como intval()
es una buena idea para valores enteros antes de enviar cualquier consulta. Además, prevenir los datos maliciosos del usuario antes de enviar la consulta es un enfoque correcto y válido .
Consulte esta pregunta para obtener más detalles: PDO envía consultas sin formato a MySQL mientras Mysqli envía consultas preparadas, ambas producen el mismo resultado
Referencias
- Hoja de trucos de inyección SQL
- Inyección SQL
- Seguridad de información
- Principios de seguridad
- Validación de datos