Las otras respuestas ya cubren lo que necesita saber. Pero quizás ayude aclarar un poco más:
Hay DOS COSAS que debe hacer:
1. Valide los datos del formulario.
Como muestra muy claramente la respuesta de Jonathan Hobbs , la elección del elemento html para la entrada del formulario no realiza ningún filtrado confiable por usted.
La validación generalmente se realiza de una manera que no altera los datos, pero que muestra el formulario nuevamente, con los campos marcados como "Corrija esto".
La mayoría de los frameworks y CMS tienen constructores de formularios que le ayudan con esta tarea. Y no solo eso, también ayudan contra CSRF (o "XSRF"), que es otra forma de ataque.
2. Desinfectar / escapar variables en sentencias SQL.
.. o deje que las declaraciones preparadas hagan el trabajo por usted.
Si crea una declaración (Mi) SQL con cualquier variable, proporcionada por el usuario o no, debe escapar y citar estas variables.
En general, cualquier variable que inserte en una declaración de MySQL debe ser una cadena o algo que PHP pueda convertir de manera confiable en una cadena que MySQL pueda digerir. Como números.
Para las cadenas, debe elegir uno de varios métodos para escapar de la cadena, es decir, reemplazar cualquier carácter que pueda tener efectos secundarios en MySQL.
- En MySQL + PHP de la vieja escuela, mysql_real_escape_string () hace el trabajo. El problema es que es demasiado fácil de olvidar, por lo que debería utilizar absolutamente declaraciones preparadas o constructores de consultas.
- En MySQLi, puede utilizar declaraciones preparadas.
- La mayoría de los frameworks y CMS proporcionan generadores de consultas que le ayudan con esta tarea.
Si se trata de un número, puede omitir el escape y las comillas (es por eso que las declaraciones preparadas permiten especificar un tipo).
Es importante señalar que se escapan las variables para la declaración SQL y NO para la base de datos en sí . La base de datos almacenará la cadena original, pero la declaración necesita una versión de escape.
¿Qué sucede si omite uno de estos?
Si no usa la validación de formularios , pero desinfecta su entrada SQL, es posible que vea todo tipo de cosas malas, ¡pero no verá la inyección SQL! (*)
Primero, puede llevar su solicitud a un estado que no planeó. Por ejemplo, si desea calcular la edad promedio de todos los usuarios, pero un usuario dio "aljkdfaqer" para la edad, su cálculo fallará.
En segundo lugar, puede haber todo tipo de otros ataques de inyección que debe considerar: por ejemplo, la entrada del usuario podría contener javascript u otras cosas.
Aún puede haber problemas con la base de datos: por ejemplo, si un campo (columna de la tabla de la base de datos) tiene un límite de 255 caracteres y la cadena es más larga. O si el campo solo acepta números y, en su lugar, intenta guardar una cadena no numérica. Pero esto no es una "inyección", es simplemente "bloquear la aplicación".
Pero, incluso si tiene un campo de texto libre donde permite cualquier entrada sin validación en absoluto, aún puede guardar esto en la base de datos así, si lo escapa correctamente cuando va a una declaración de base de datos. El problema surge cuando quieres usar esta cadena en alguna parte.
(*) o esto sería algo realmente exótico.
Si no escapa de las variables para las declaraciones SQL , pero sí validó la entrada del formulario, aún puede ver que suceden cosas malas.
En primer lugar, corre el riesgo de que cuando guarde datos en la base de datos y los vuelva a cargar, ya no sean los mismos datos, "perdidos en la traducción".
En segundo lugar, puede generar declaraciones SQL no válidas y, por lo tanto, bloquear su aplicación. Por ejemplo, si alguna variable contiene una comilla o un carácter de comilla doble, según el tipo de cita que utilice, obtendrá una declaración MySQL no válida.
En tercer lugar, todavía puede provocar una inyección SQL.
Si la entrada de usuario de los formularios ya está filtrada / validada, la inyección intencional de SQl puede volverse menos probable, SI su entrada se reduce a una lista codificada de opciones o si está restringida a números. Pero cualquier entrada de texto libre se puede utilizar para la inyección de SQL, si no se escapan correctamente las variables en las declaraciones de SQL.
E incluso si no tiene ninguna entrada de formulario, aún podría tener cadenas de todo tipo de fuentes: leídas del sistema de archivos, extraídas de Internet, etc. Nadie puede garantizar que estas cadenas sean seguras.
<select>
entrada. De hecho, incluso un usuario ligeramente técnico podría agregar opciones adicionales utilizando la consola del navegador. si mantiene una lista blanca de matriz de valores disponibles y compara la entrada con ella, puede mitigar eso (y debería hacerlo porque evita valores no deseados)