Hola a todos,
El uso de funciones como mysql_real_escape_string no siempre asegura un nivel de seguridad aceptable, aunque lo mejora.
Para empezar, hay muchas vulnerabilidades que evitar, y por lo tanto depende mucho del tipo de login, autentificación o formulario.
1. Para evitar inyecciones SQL es necesario usar siempre mysql_real_escape_string en cada una de las variables que se pasan a la base de datos, y además de eso, colocar todas las variables entrecomilladas. Me explico:
$id = mysql_real_escape_string($_POST['id'])
mysql_query("SELECT ... WHERE id={$id}"); // VULNERABLE
mysql_query("SELECT ... WHERE id='{$id}' "); // NO VULNERABLE
2. Además, todos los parámetros deben pasar por un filtro que evite etiquetas HTML para evitar ataques por XSS. Ya hemos hablado mucho de esto: htmlentities, strip_tags, specialchars y demás.
La mayoría de la gente suele evitar XSS en username, nombre, apellidos... pero es necesario pasarlo en TODOS los campos.
Un campo de web puede contener código XSS, un campo email también y todos los campos pueden contenerlo.
Una máxima en seguridad web es asegurar TODOS, ABSOLUTAMENTE TODOS los datos que se insertan en una web, tengan la importancia en la lógica del script que tengan.
3. Además de eso, si usas cookies para permanecer en el login, también deben asegurarse los datos de las cookies, contra XSS y contra SQLi. Vuelvo a repetir, todo lo que se envía a una web y va a ser guardado o procesado debe pasar por esos filtros.
4. No creo que sea el caso, pero en los login multipasos hay que tener MUCHO cuidado, porque pueden ser fácilmente salteados, variando la secuencia de páginas para ingresar y modificando campos que se envían entre pasos.
5. Mucho cuidado también con los campos HIDDEN. Los campos hidden son campos como otros cualquiera, y pueden modificarse fácilmente con herramientas que se pueden encontrar con facilidad. De nuevo, TODO lo que entra y se procesa en la web tiene que pasar el filtro Anti-XSS y Anti-SQLi
6. El sistema de login debe tener un sistema captcha. Esta medida se debe combinar con sugerir FUERTEMENTE a los usuarios colocar una clave segura. Además, debe colocarse una longitud de password mínimo razonable, y intentar usar el máximo rango de caracteres posibles. Lo ideal sería numeros, letras y caracteres especiales ($%&# y demás) pero esto depende en gran medida del usuario, y hay que tener en cuenta que probablemente la mayoría no lo harán.
7. Un fallo muy común es indicar en un login cual de los dos campos (usuario o contraseña) no es introducido correctamente. Un login en el que se indique "El usuario introducido no existe" se puede bruteforcear (es decir, introducir muchos valores en poco tiempo con un automatismo) para sacar usuarios que existen a partir de los errores que se devuelven, como el mencionado anteriormente, y a partir de ahí bruteforcear el campo de passwords para sacar una contraseña en un nombre de usuario que conozcamos.
Esta debilidad también se encuentra en un registro. Cuando se introduce un usuario ya existente normalmente se le suele advertir al usuario de que ese nombre ya está cogido, con lo que se puede bruteforcear un registro de usuarios para ver que nombres de usuario existen, y así conseguir passwords débiles.
Soluciones: usar captcha en el login tras un número de intentos fallidos (por ejemplo 3, o 5) y igual en el registro de usuarios. Introducir un captcha directamente puede ser muy molesto para los usuarios, así que solo introducelo cuando falle varias veces (imagina que tubieras que rellenar un captcha cada vez que quieres acceder a Facebook o Twitter).
8. Cuidado con la forma en la que contabilizas los intentos fallidos en formularios. Si envías una cookie con el número de intentos fallidos, y haces saltar tu sistema antibot (como captcha) despues de, por ejemplo, 5 intentos, se podría automatizar un bot que borrara las cookies cada 3 o 4 intentos de forma que no se detectaría.
Utilizar una sesión parece lo mas adecuado, pero hay que tener cuidado con que guardar. El campo $_SERVER['REMOTE_ADDR'] es más seguro que $_SERVER['HTTP_X_FORWARDED_FOR'], ya que esta última puede modificarse fácilmente.
9. Si es posible, nunca muestres keys de la base de datos (como las id) en tu sitio web. Evita cosas como
http://miweb.com/usuarios.php?id=2Con cosas así puede saberse que id pertenece a que usuario, y usar esa información para explotar otra vulnerabilidad.
10. Cuidado con los file paths! He visto muchos "sistemas de modulación" (como se le suele decir por aquí) que al incluir archivos no comparan con unos archivos esperados, y la gente puede incluir cualquier archivo con un poco de imaginación.
http://miweb.com/noticias/?pagina=../index.php~Lo correcto es crear un array con páginas aceptables, por ejemplo array("noticia1.php", "noticia2.php", etc); y comparar la variable pasada con esa array (con la función in_array) y si no existe coincidencia mostrar un error.
11. Cuidado con el archivo robots
Cualquiera puede leer ese archivo, no solo los buscadores, y por lo tanto meter ahí direcciones como paneles de administración puede acabar en filtrar urls privadas.
12. Nunca creas que por llamar a un directorio asdasdas_dasd12312r no lo van a descubrir. Poner un nombre de directorio aleatorio NO ES SEGURO, habrá que implementar un sistema de autentificación o login para ese directorio, pero desde luego hay que protegerlo. Es cierto que puede dificultar que lo encuentren, pero puede filtrarse fácilmente, es mejor no jugársela.
13. Recuerda que muchas de las variables en $_SERVER y en $_COOKIE y demás pueden sobreescribirse y modificarse en el cliente, por lo tanto no es buena idea fiarse de ellas para temas de autentificación. Permitir a un usuario entrar en X página si su navegador es "Navegador de MiWeb.com" no se puede considerar seguro porque cualquiera puede modificar esa variable y aplicarse el título de ese navegador sin poseerlo. Lo que quiero decir básicamente es que NUNCA puedes fiarte de lo que te envíe un usuario.
14. Cuidado con los permisos de los archivos y directorios. Tener permisos 777 en todos los directorios puede explotarse mediante otra vulnerabilidad. Cada directorio y archivo debe tener los permisos que necesita. Ni más, ni menos.
15. Vulnerabilidades en la lógica de los scripts PHP puede haber innumerables, eso ya depende de tu forma de programar. Ten siempre cuidado con lo que programas, y nunca dejes nada suelto. Nunca supongas "Bah, esto el usuario no lo sabrá." o cosas por el estilo. Siempre debes imaginar que va a existir un usuario malintencionado que va a querer jugártela.
16. Como te han dicho, cuando estés en produccion (dejes de hacer pruebas) es mejor usar @ en la funciones para filtrar errores que podrían dar información de más a usuarios malintencionados.
Si creen que algo está mal o tienen una mejor idea no duden en comentarlo.
Un saludo, y perdón por el post tan largo.