8 reglas sencillas para desarrollar un código más seguro

Publicado: noviembre 30, 2007 en Categoria All

8 reglas sencillas para desarrollar un código más seguro


  • Uso de herramientas de análisis y recurso a expertos para revisar el código
  • Reducción de riesgos mediante pruebas aleatorias y modelado de amenazas
  • Supresión de entradas incorrectas en las aplicaciones
  • Más información acerca de los conceptos sobre seguridad

Contents

Hábito N.º 1: Asumir la responsabilidad
Hábito N.º 2: No confíe nunca en los datos
Hábito N.º 3: Diseñe amenazas contra su código
Hábito N.º 4: Vaya un paso por delante
Hábito N.º 5: Realice pruebas aleatorias
Hábito N.º 6: No escriba código no seguro
Hábito N.º 7: Reconozca la asimetría estratégica
Hábito N.º 8: Use las mejores herramientas que pueda


He tenido la suerte de trabajar a lo largo de los años con un gran número de buenos desarrolladores que deseaban aprender a programar software más seguro. Durante ese tiempo, también he aprendido mucho de personas capaces de crear sistemas seguros excelentes, y eso me ha dado mucho que pensar. Me preguntaba si había aptitudes o hábitos comunes que comparten los “desarrolladores seguros”. Resulta que la respuesta es afirmativa, sin duda alguna. En este artículo se presenta esa relación de hábitos que comparten los desarrolladores de código seguro.

De lo que no me cabe duda es que quien vea esta lista detectará de inmediato que faltan hábitos. Me parece muy bien. Sé que hay otras ideas muy buenas sobre este asunto. Peo ésta es la lista que he elaborado yo. Dicho esto, procederé a señalar los hábitos ejemplares que he detectado a lo largo de los años.

Hábito N.º 1: Asumir la responsabilidad

Es una variante del clásico comentario “No hay bala de plata” que hizo hace más de 25 años Fred Brookes en The Mythical Man Month (en inglés). Procurar mecanismos de seguridad adecuados en su producto depende totalmente de usted. Nadie más (ni, por supuesto, ningún lenguaje de programación ni herramienta mágica) puede solucionar todas las lagunas de seguridad. No quiero que me malinterpreten: me gustan las herramientas de análisis de código fuente, pero no solucionarán mágicamente todas las vulnerabilidades de seguridad. Sólo usted puede hacerlo.

Los productos seguros son generados por desarrolladores que crean diseños seguros y escriben código seguro. Por último la escritura de código es un esfuerzo individual. El programador no puede ser reemplazado por una herramienta. Así pues, la seguridad de su producto es responsabilidad suya. Los gusanos Blaster y CodeRed se aprovechaban de código escrito por individuos (consulte la figura 1).

figura 1 código vulnerable son escritos por individuos
figura 1 código vulnerable son escritos por individuos

Recuerde que todo el código será examinado y, posiblemente, atacado. No hay ningún problema. Ser atacado es algo perfectamente normal. Lo importante es saber si su código quedará expuesto. Sólo usted puede determinar ese desenlace. Así pues, tómese en serio su código. Debe estar satisfecho con la calidad del código y poder dormir tranquilo sabiendo que, si es atacado, habrá hecho todo lo posible para impedir que lo dejen para el arrastre.

Si es posible, solicite a un experto de seguridad que revise su código. No pida que lo examine alguien sin experiencia en seguridad con la expectativa de que pueda encontrar errores de seguridad y vulnerabilidades. Procure por todos los medios recurrir a alguien que sepa realmente lo que tiene entre manos para que examine el código.

Y sea razonablemente humilde para pedir ayuda cuando la necesite. Antes comentaba que no debe confiar exclusivamente en las herramientas, pero no cabe duda de que debe aprovechar las que se encuentren a su disposición. Ejecute todas las herramientas de análisis de código fuente disponibles y hágalo con frecuencia. Aproveche cualquier construcción de lenguaje defensivo posible y todos los trucos de biblioteca que estén a su disposición. En C#, por ejemplo, ajuste el código de red que ejecute el acceso a matrices, donde el índice de matriz se derive de una solicitud de red, en operadores comprobados, para detectar posibles errores aritméticos con enteros.

Back to top

Hábito N.º 2: No confíe nunca en los datos

Lo he dicho millones de veces y volveré a decirlo: toda entrada es nociva hasta que se demuestre lo contrario. Si nos fijamos en las vulnerabilidades de seguridad más atroces, veremos que comparten un rasgo común: el desarrollador confió en los datos entrantes. El problema es que, si el código asume que el formato de los datos es correcto, ¿qué ocurre si usted se equivoca con esa suposición? Si es su día, la aplicación se bloqueará. Con algo menos de suerte, el atacante podría introducir código malintencionado en sus procesos y causar estragos.

La ambigua definición de sistema seguro corresponde a la de aquél que realiza las tareas para las que está diseñado, ni más ni menos. Pero cuando surgen problemas derivados de la confianza en las entradas, el sistema suele verse obligado a desempeñar otras tareas. Un somero análisis de datos de Common Vulnerabilities and Exposures (CVE) ( cve.mitre.org) muestra que, entre 2001 y 2004, el 47% de las vulnerabilidades de seguridad de las que CVE realizó un seguimiento fueron problemas relacionados con la confianza en las entradas. Los problemas más conocidos son saturaciones de búfer, errores aritméticos con enteros, secuencias de comandos entre sitios y errores de inyección SQL. Estamos empezando a ver nuevas variantes, como la inyección XPath y vulnerabilidades de inyección de protocolo ligero de acceso a directorios (LDAP).

Puede solucionar los problemas relacionados con la confianza en las entradas si aplica algunas normas simples. En primer lugar, no busque únicamente lo que le consta que tiene un efecto adverso; con ese planteamiento parte de la base de que conoce todo lo negativo y puede predecir lo que ocurrirá en el futuro. Buscar factores con efectos nocivos es una buena iniciativa siempre que no sea su único mecanismo de defensa. Una estrategia mejor consiste en restringir la entrada a lo que le consta que es adecuado. Con lenguajes de alto nivel, como C# y Perl, me gusta usar expresiones regulares para hacerlo.

A continuación, rechace lo que le conste que es perjudicial. Por ejemplo, si alguien solicita de forma remota un archivo a través de su código y el nombre del archivo incluye un carácter poco confiable (como : o \), rechace la solicitud. Y no le diga al atacante por qué; limítese a indicar “no se encontró el archivo”.

Por último, aunque esto no sirve en todas las situaciones, sanee los datos. Por ejemplo, en el caso de un servidor Web, debe codificar con HTML la salida procedente de una entrada potencialmente no fidedigna.

Back to top

Hábito N.º 3: Diseñe amenazas contra su código

Dispone de modelos de amenazas, ¿verdad? Los modelos de amenazas le permiten comprender los riesgos potenciales para su software y asegurarse de que dispone de los remedios apropiados. Pero las ventajas del uso de modelos de amenazas no se limitan a un diseño seguro. Los modelos de amenazas pueden contribuir también a mejorar la calidad del código. Los modelos de amenazas le indican de dónde proceden los datos. ¿Se trata de datos locales o remotos? ¿Proceden los datos de usuarios anónimos o de usuarios de mayor confianza (autenticados), como los administradores?

Con esta información, puede determinar si sus defensas son apropiadas. Por ejemplo, el código al que pueden tener acceso usuarios anónimos y remotos tiene que ser muy seguro. No digo que el código al que sólo puedan tener acceso los administradores locales no debería ser seguro, sino que el código accesible de forma remota, sobre todo el que se ejecuta de manera predeterminada, debe ser a prueba de bombas; y eso implica más mecanismos de defensa, más revisiones y más atención a los detalles. Además, el modelo de amenazas puede indicarle la naturaleza de los datos que se protegen. Los datos empresariales de gran valor y la información personal identificable deben protegerse muy bien. ¿Son apropiadas sus defensas?

Asegúrese de que sus modelos de amenazas sean precisos y estén actualizados; después identifique todos los puntos de entrada en su código y clasifíquelos por accesibilidad: remotos o locales y usuarios con privilegios elevados frente a usuarios con pocos privilegios (o sin privilegios). El código más accesible debe revisarse en primer lugar y con mayor detenimiento. Por último, revise todo el código en las rutas de datos anónimos; dicho de otro modo, empiece por los puntos de entrada a los que se pueda tener acceso anónimamente y rastree los datos a lo largo de esa ruta, para asegurarse de que el código es correcto.

Back to top

Hábito N.º 4: Vaya un paso por delante

El panorama de la seguridad evoluciona constantemente. Parece que cada semana hay nuevas variaciones con respecto a las cuestiones de seguridad. Esto significa que debe evolucionar y aprender acerca de nuevas amenazas y defensas, o sufrirá las consecuencias.

Algunas estrategias sencillas para mantenerse al día consisten en leer de vez en cuando algún buen libro sobre seguridad de software. Aprenda también de sus errores del pasado; mejor aún si se trata de los errores cometidos por otros. Para ello, puede leer bugtraq: vaya a securityfocus.com y regístrese para recibir mensajes de bugtraq en su bandeja de entrada. Pero acepte este pequeño consejo: cree una regla de la bandeja de entrada para mover los mensajes a una carpeta especial, de modo que pueda administrar el volumen. Es considerable.

Back to top

Hábito N.º 5: Realice pruebas aleatorias

Las pruebas aleatorias permiten detectar errores de confiabilidad. Resulta que un porcentaje de los errores de confiabilidad corresponde a vulnerabilidades en la seguridad a la espera del “ataque adecuado”. Por supuesto, una saturación de búfer podría provocar el bloqueo de una aplicación; pero con una carga malintencionada bien diseñada, el atacante podría evitar el bloqueo y ejecutar código para sus propios fines. Nuestro lema para esos casos es “la denegación del servicio de hoy es la ejecución del código de mañana.”

Casi todos los errores o vulnerabilidades de análisis de archivos se detectaron por puro azar o por pruebas aleatorias. Microsoft ha detectado vulnerabilidades de seguridad analizando distintos formatos de archivo, como los correspondientes a archivos XLS, PPT, DOC y BMP. La mayoría de los fabricantes habían tenido vulnerabilidades similares, ya que el análisis de estructuras de datos complejas es una tarea complicada, el código complejo presentará errores y algunos de esos errores revelarán vulnerabilidades de seguridad.

Debe probar aleatoriamente todo el código que analice archivos y tráfico de red. El ciclo de vida de desarrollo de seguridad (SDL) de Microsoft es muy específico acerca de lo que esto significa para los formatos de archivo. Debe probar aleatoriamente todos los analizadores con 100.000 iteraciones de archivos con formato incorrecto mediante un comprobador aleatorio de archivos. Hay varios comprobadores aleatorios disponibles que funcionan correctamente, e incluimos un comprobador de archivos, así como código fuente C++, en el manual The Security Development Lifecycle (en inglés), que elaboré conjuntamente con Steve Lipner (microsoft.com/MSPress/books/8753.asp).

Una última nota acerca de las pruebas aleatorias. Si se bloquea el software, no crea que se trata de un bloqueo únicamente. Es probable que un porcentaje considerable de esos supuestos bloqueos estén invitando a que algún atacante escriba código malintencionado. Por lo tanto, no vea en un bloqueo “un mero bloqueo”.

Back to top

Hábito N.º 6: No escriba código no seguro

En Microsoft usamos el concepto de puertas o compuertas de calidad para reducir las posibilidades de que un desarrollador introduzca código vulnerable en el producto. Estas “compuertas” ejecutan una batería de herramientas de análisis de código fuente en el código antes de proceder a su protección para señalar los problemas que pueda haber. Y los problemas identificados deben solucionarse antes de que se lleve a cabo la protección. También puede hacer que se apliquen reglas de código estrictas, como la exclusión del uso de funciones prohibidas, como la ausencia de llamadas a strcpy o strncat y el cifrado deficiente. (Microsoft ha prohibido más de 100 funciones de C en tiempo de ejecución para nuevo código). Por ejemplo, con relación al cifrado, no permitimos DES (la longitud de la clave es demasiado reducida), MD4 o MD5 (ya se han superado) en el código nuevo, a menos que un estándar del sector dicte su uso.

No reinvente funciones. Si tiene un código que analiza un formato de archivo determinado, no necesitará dos o tres conjuntos de código de análisis; aténgase a un conjunto, consolídelo y ajústelo de manera que pueda usarse en varios proyectos.

Por último, recuerde que las herramientas no son un sustituto para la escritura de código seguro. Por eso es tan importante la formación en materia de seguridad y privacidad. Necesita una comprensión sólida de los conceptos para tomar decisiones en conciencia y adquirir nuevas percepciones, algo inasequible para las herramientas.

Back to top

Hábito N.º 7: Reconozca la asimetría estratégica

Ésta es una de mis cuestiones preferidas. Recuerde que, como desarrollador de software, las estadísticas en materia de seguridad van contra usted. Yo suelo llamarlo “la ventaja del atacante y el dilema del defensor”. Necesitaría que el código y los diseños fueran correctos al 100% en todo momento, y eso es imposible. Para empeorar las cosas, debe alcanzar el insuperable objetivo con un presupuesto fijo y a tiempo, mientras tiene que considerar los requisitos de compatibilidad, accesibilidad y otras “ades”. Un atacante puede dedicar todo el tiempo que desee para localizar un error y después anunciar al mundo que su aplicación no es segura.

En el hábito N.º 6 señalé que debería dejar de escribir nuevo código inseguro. Para el hábito N.º 7 tiene que concentrarse en todo el código, porque los atacantes no hacen distinciones en lo que respecta a la antigüedad. Dedique tiempo a revisar vulnerabilidades en el código antiguo, y considere seriamente la posibilidad de desechar funciones antiguas e inseguras. Si usa métodos de desarrollo ágiles, debe pensar en dedicar esfuerzos a corregir código antiguo para situarlo en el nivel de calidad del código más reciente.

Back to top

Hábito N.º 8: Use las mejores herramientas que pueda

Por último, use las mejores herramientas que le sea posible. Me encantan las herramientas de análisis de código fuente y la tecnología que me ayuda a escribir código más seguro. Como señalé antes, las herramientas no son la panacea, pero ayudan. Y mucho. Las herramientas también facilitan la racionalización del problema del análisis de código fuente. Las herramientas pueden explorar grandes cantidades de código con rapidez, mucho más que una persona. Y esto le ayuda a hacerse una idea de lo “malo” que puede llegar a ser un determinado código.

Uno de mis trucos preferidos consiste en compilar código con los niveles de advertencia más altos que sea posible; por ejemplo, /W4 cuando uso Visual C++® o –Wall cuando uso gcc. Si ve un gran número de advertencias en el código, quizá éste presente otros errores que no detectaron el compilador u otras herramientas. Ese código debería someterse a un escrutinio más detenido antes de su lanzamiento (consulte el hábito N.º 3).

Éstos son ocho buenos hábitos que he observado en desarrolladores a los que respeto enormemente, y que trabajan tanto para Microsoft como para otros fabricantes. Por sí solos, los hábitos no le convertirán en un desarrollador seguro estelar, pero no cabe dudad de que le ayudarán.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s