Muchos de nosotros nos enfrentamos día a día a la necesidad de programar procesos críticos, muchas veces accesibles a miles de usuarios presumiblemente hostiles (por ejemplo, un CGI web), y cuyo compromiso puede poner en peligro la integridad o la seguridad de todo el sistema. Procesos necesarios, sin los que no se puede vivir, pero de los que nos gustaría poder prescindir porque su misma existencia supone un riesgo. En casos así, resulta imprescindible el seguir una metodología clara y detallada para intentar hacer al programa lo más robusto, fiable y seguro que sea posible.
En este artículo vamos a intentar dar algunos consejos para la programación segura en C. Al final del texto incluiré también algunas referencias que serán útiles a los programadores de PERL, ya que es un lenguaje que yo apenas utilizo.
Lo primero que hay que decir es que escribir código seguro dista mucho de ser una tarea trivial. Existe abundante bibliografía sobre el tema, pero tristemente comprobamos como, día a día, los programadores cometen (cometemos) los mismos errores una y otra vez. Muchos programadores no son conscientes de los riesgos de seguridad que corren los administradores que instalan sus programas y, en otros casos, sencillamente somos lo bastante humanos como para cometer errores. Lamentablemente un error en estos entornos es algo que nos puede costar muy caro.
Programar de forma segura, aunque no excesivamente complicado, sí resulta tedioso y proclive a fallos. Además de lidiar con los tópicos e inevitables "bugs" en los programas, debemos hacer gala de una sana pero extrema paranoia. No fiarnos de nadie. No fiarnos de nada. No dormir por las noches. Curarnos en salud, por así decirlo, si no nos morimos antes de agotamiento o falta de sueño.
Resulta útil analizar con lupa las especificaciones funcionales del programa. Las clasificaciones siempre son útiles para aclarar ideas:
- Condiciones internas al programa
Son debidas a bugs o presunciones dentro de nuestro propio código. Un ejemplo clásico son los errores de desbordamiento debido a funciones como "strcpy()".
- Condiciones externas al programa
Aquí nos estamos enfrentando a circunstancias exteriores no sujetas a nuestro control: enlaces simbólicos en vez de ficheros regulares, directorios/ficheros públicos, "race conditions", interacciones con otros programas o el sistema operativo, etc.
- Ataques remotos
Los ataques remotos son aquellos que tienen lugar a través de una red, como puede ser Internet. Evidentemente, sólo tendremos que preocuparnos de ellos si el programa que estamos creando es accesible desde el exterior.
- Ataques locales
Los ataques locales cubren aquellos llevados a cabo dentro del entorno del programa, ya sea de forma accidental o debido a un usuario malicioso. Los usuarios locales son siempre mucho más peligrosos que cualquier hacker de internet, ya que su acceso es infinitamente más abierto. Además, un usuario local siempre está a tiempo de desencadenar un ataque remoto con un simple "Telnet" a su misma máquina.
Para que este artículo tenga un tamaño manejable (el tema es lo suficientemente amplio como para escribir un libro) no tengo más remedio que conformarme con publicar poco más que un esquema. Un esquema grande y complejo, eso sí. Espero que sirva para salvar el día a más de uno.