Programación defensiva


Programación defensiva

Programación defensiva

La programación defensiva (defensive programming en inglés) es una forma de diseño defensivo aplicada al diseño de software que busca garantizar el comportamiento de todo elemento de una aplicación ante cualquier situación de uso por incorrecta o imprevisible que ésta pueda parecer. En general, esto supone multiplicar las comprobaciones que se realizan en todos los módulos programados, con la consiguiente penalización en carga de procesador, tiempo y aumento en la complejidad del código. Las técnicas de programación defensiva se utilizan especialmente en componentes críticos cuyo mal funcionamiento, ya sea por descuido o por ataque malicioso, podría acarrear consecuencias graves o daños catastróficos.

La programación defensiva es un enfoque que busca mejorar el software y el código fuente, en términos de:

  • Calidad General - reduciendo el número de fallos de software y problemas.
  • Haciendo el código fuente comprensible - el código fuente debe ser legible y entendible, a prueba de una auditoría de código.
  • Hacer que el software se comporte de una manera predecible pese a entradas o acciones de usuario inesperadas.

Contenido

Programación segura

La programación defensiva es algunas veces referida como programación segura por los científicos de computación los cuales ubican este enfoque minimizando bugs.

Los errores de software (bugs) pueden ser potencialmente usados por un cracker para una inyección de código, ataques de denegación de servicio u otro ataque.

Una diferencia entre programación defensiva y prácticas normales es que pocas hipótesis son hechas por el programador, el cual intenta manejar todos los posibles estados de error. En resumen, el programador nunca asume que una llamada a una función particular o librería trabajará bajo las entradas previstas.

Algunas técnicas de programación defensiva

Aquí están algunas técnicas de programación defensiva sugeridas por algunos de los científicos líderes de computación para evitar crear problemas de seguridad y errores de software. Estos científicos afirman que aunque este proceso pueda mejorar la calidad el código, no es suficiente para asegurar la seguridad. Mirar artículos sobre inseguridad computacional o programación segura para más información.

Los principios de programación para crear software defensivo son:

Reducir complejidad del código fuente

Nunca hacer el código más complejo que lo necesario. La complejidad genera bugs, incluyendo problemas de seguridad. Esta meta pude tener conflicto con el objetivo de escribir programas que puedan recuperarse de cualquier error y manejar cualquier entrada de datos. Manejar todas las ocurrencias inesperadas en un programa requiere que el programador adicione código extra, el cual pudiera también tener bugs.

Revisiones del código fuente

Una revisión de código es donde alguien diferente al autor original realiza una auditoría de código. Una auditoría de código hecha por el mismo creador es insuficiente. La auditoría la debe hacer alguien que no sea el autor, como cuando se escribe un libro, debe ser revisado por alguien que no sea el autor.

Simplemente haciendo el código disponible para que otros lo lean (Ver Software Libre, o Open Source Definition) es insuficiente: no hay garantía que el código sea visto, no dejando que sea rigurosamente revisado.

Pruebas de software

Las pruebas de software deberán ser para tanto que el software trabaje como debe, como cuando se supone que pase si se realice deliberadamente malas entradas.

Las herramientas de prueba pueden capturar entradas de teclado asociadas con operaciones normales. Luego las cadenas de texto de estas entradas capturadas pueden ser copiadas y editadas para ensayar todas las permutaciones y combinaciones, luego ampliarlas para tests posteriores después de cualquier modificación-. Los defensores de la clave de registro afirman que los programadores que usan este método deberán asegurar que las personas a las cuales se les están capturando las entradas estén al tanto de esto, y con que propósito?, para evitar acusaciones de violación de privacidad .

Reutilización inteligente del código fuente

Si es posible, reutilizar código. La idea es capturar beneficios de un bien escrito y bien probado código fuente, en vez de crear bugs innecesarios.

Sin embargo, reutilizar código no siempre es la mejor manera de progresar, particularmente cuando la lógica del negocio esta involucrada. Reutilizar en este caso puede causar serios bugs en los procesos de negocio.

Los problemas de legado

Antes de reutilizar viejo código fuente, librerías, API’s, configuración y demás, debe ser considerado si el trabajo anterior es válido para reutilizar, o si es propenso a problemas de legado.

Los problemas de legado son problemas inherentes cuando se espera que viejos diseños trabajen con los requerimientos actuales, especialmente cuando estos viejos diseños no fueron desarrollados o probados con estos requerimientos en mente.

Muchos productos de software han experimentado problemas con viejos códigos fuente legados, por ejemplo:

  • El código legado puede no haber sido diseñado bajo iniciativa de Programación Defensiva, y puede por consiguiente estar con mucha menor calidad que un diseño más nuevo de código fuente
  • El código legado puede haber sido escrito y probado bajo condiciones que ya no aplican más. Los viejos test de aseguramiento de calidad pueden no ser válidos ahora. Ejemplo 1: El código legado puede haber sido diseñado para entradas ASCII pero ahora la entrada es UTF-8. Ejemplo 2: El código legado puede haber sido compilado y probado sobre arquitecturas de 32 bits, pero cuando es compilado sobre arquitecturas de 64 bits pueden ocurrir nuevos problemas aritméticos. Ejemplo 3: Un código legado puede haberse enfocado hacia máquinas fuera de línea, pero se vuelve vulnerable una vez la conectividad de red es adicionada.
  • El código legado no es escrito con nuevos problemas en mente. Por ejemplo, código fuente escrito en 1990, puede ser propenso a vulnerabilidades de Inyección de Código, porque muchos de estos problemas no eran extensamente entendidos en esa época

Ejemplos notables de problemas de legado:

  • BIND 9, presentado por Paul Vixie y David Conrad como “BINDv9 es una completa reescritura”, “La seguridad fue una consideración clave en diseño”, nombrando seguridad, robustez, escalabilidad y nuevos protocolos como preocupaciones clave para reescribir viejo código legado.
  • Microsoft Windows sufrió de el “Windows Metafile Vulnerability” y otras explotaciones referentes al formato WMF, El centro de respuesta de seguridad de Microsoft describe que características de WMF como “ Alrededor de 1990, el soporte WMF fue adicionado…. Este fue un tiempo diferente en el paisaje de seguridad….estábamos todos completamente confiados….”.
  • Oracle está combatiendo problemas de legado, como el viejo código fuente escrito sin direccional preocupaciones respecto a la inyección SQL y Escalas de Privilegio, resultando en muchas vulnerabilidades de seguridad las cuales han tomado tiempo en ser arregladas y han generado arreglos incompletos. Esto le ha levantado pesadas críticas de los expertos de seguridad como David Litchfield, Alexander Kombrust, Cesar Cerrado. Una crítica adicional es que las instalaciones por defecto (largamente un legado de viejas versiones) no se encuentra alineado con sus propias recomendaciones de seguridad, como el Oracle Database Security Checklist, el cual es difícil de enmendar.

Entrada segura / manejo de la salida

Canonicalizar

Los crackers tienden a inventar nuevos tipos de representaciones de datos incorrectas

Por ejemplo, si se revisa si un archivo pedido o es “/etc/passwd”, un cracker puede pasar otra variante de este nombre de archivo como “/etc/,/passwd”

Para evitar bugs debido a entradas no canónicas, emplear los Canonicalization API’s

Principio del menor privilegio

Emplear el principio del menor privilegio, Evitar tener software corriendo en un modo privilegiado:

  • Nunca hacer programas UNIX setuid a menos que se este realmente seguro que se esta protegiendo la seguridad.
  • Nunca hacer programas de Windows correr como servicios de sistema local a menos que se este realmente seguro que se está protegiendo la seguridad.
  • No conceder más permisos que los necesarios a grandes grupos de usuarios o público/cualquiera.
  • No conceder más permisos que los necesarios a grupos pequeños de usuarios o usuarios específicos.
  • Preferir conceder permisos a grupos pequeños de usuarios o usuarios específico, en vez de concederlos a grandes grupos de usuarios o público/cualquiera. Es mejor que unos pocos usuarios tengan mas permisos, que muchos usuarios tengan mayor permiso.

Baja tolerancia contra “potenciales” bugs

Asumir que el código construido que parece ser propenso a problemas (similares a conocidas vulnerabilidades, etc), son errores (bugs) o potenciales fallos de seguridad. La regla básica es: “No estoy al tanto de todos los tipos de explotaciones de seguridad” Debo proteger en contra de lo que conozco y así tengo que ser proactivo”

Otras técnicas

  • Uno de los problemas más comunes es uso no verificado de estructuras de tamaño constante y funciones de tamaño de datos dinámicos (el problema del desbordamiento de buffer). Esto es especialmente común en la gestión de cadenas de texto en lenguaje C. Las funciones de librería C como gets nunca deberían ser usadas si el tamaño máximo del buffer de entrada no se pasa como argumento. Las funciones de librería en C como scanf pueden ser usadas seguramente, pero requieren que el programador tenga cuidado con la selección de los formatos seguros de strings, cuidándose antes de usarlos.
  • Cifrar/ Autenticar todos los datos importantes transmitido sobre las redes. No intentar implementar un propio esquema de cifrado, pero usar uno ya probado.
  • Todos los datos son importantes hasta que se demuestre lo contrario.
  • Todos los datos están viciados hasta que se demuestre lo contrario.
  • Todo código es inseguro hasta que se demuestre lo contrario.
  • Si los datos son probados por correctitud, verificar que están correctos, no que están incorrectos.
  • Diseño por contrato: El diseño por contrato usa precondiciones, postcondiciones e invariantes para asegurar que los datos provistos (y el estado del programa como un todo) esta saneado. Esto permite al código documentar todas las hipótesis y hacerlo así seguro. Esto puede envolver la verificación de argumentos a una función o método para validar antes de ejecutar el cuerpo de la función. Después del cuerpo de la función, hacer un chequeo del estado del objeto (en lenguajes de programación orientada a objetos) o guardar los datos y el valor de retorno, antes de que salga de la misma (break/ return/ throw/ error code) es también sabio.
  • Aserciones: Entre funciones, se puede querer verificar que se esta referenciando algo que no es valido (ej: null) y que el tamaño de los arreglos son válidos antes de referenciar elementos, especialmente instanciando de forma temporal/local. Una buena heurística es no creer en las librerías que se hayan o no se hayan escrito. Cada vez que se llamen estas, verificar lo que se quiere que estas devuelvan. A veces ayuda crear una pequeña librería de funciones de “aserción” y “verificación” para hacerla junto a un logger, para así poder trazar la ruta y reducir la necesidad de extensos ciclos de depuración. Con la llegada de librerías de loggeo y la Programación orientada al Aspecto, muchos de los tediosos aspectos de la programación defensiva son mitigados.
  • Preferir el uso de excepciones programables frente a la sobrecarga de los valores de retorno enviando como valores no útiles códigos de error.

Enlaces externos

Obtenido de "Programaci%C3%B3n defensiva"

Wikimedia foundation. 2010.

Mira otros diccionarios:

  • Separación de privilegios — En programación, separación de privilegios es una técnica que se usa para atenuar el daño potencial de un ataque a la seguridad de una computadora. En su forma más básica, un programa de computadora se bifurca en dos procesos. El programa… …   Wikipedia Español

  • Diseño defensivo — Saltar a navegación, búsqueda El diseño defensivo es una técnica de diseño empleada para evitar que se den contingencias en el uso de dispositivos, objetos, procedimientos o rutinas. Con él se busca evitar que el usuario final pueda ocasionar… …   Wikipedia Español

  • Anexo:Episodios de Naruto — Este artículo o sección necesita referencias que aparezcan en una publicación acreditada, como revistas especializadas, monografías, prensa diaria o páginas de Internet fidedignas. Puedes añadirlas así o avisar …   Wikipedia Español

  • Radio — I (Del lat. radius, varita, rayo de luz.) ► sustantivo masculino 1 GEOMETRÍA Distancia o línea recta que une un punto de una circunferencia o de la superficie de una esfera con su centro. 2 Espacio circular definido por esta línea: ■ en un radio… …   Enciclopedia Universal

  • México — Para otros usos de este término, véase México (desambiguación). «Mexicano» redirige aquí. Para otras acepciones, véase Mexicano (desambiguación). «Mexicana» redirige aquí. Para la aerolínea, véase Mexicana de Aviación …   Wikipedia Español

  • Granada — Para otros usos de este término, véase Granada (desambiguación). Granada …   Wikipedia Español

  • Saab 39 Gripen — La exactitud de la información en este artículo o sección está discutida. En la página de discusión puedes consultar el debate al respecto …   Wikipedia Español

  • Basketsim — Saltar a navegación, búsqueda Basketsim es un videojuego de navegador gratuito en el que el jugador gestiona un equipo de baloncesto. Contenido 1 Características 2 Historia 3 Supporter …   Wikipedia Español

  • Martos — Martos …   Wikipedia Español

  • StarCraft — Distribuidora(s) Windows / Mac: Blizzard Entertainment Sierra Entertainment Nintendo 64: Nintendo Creador(es) Chris Metzen Diseñador(es) Blizzard Ente …   Wikipedia Español


Compartir el artículo y extractos

Link directo
Do a right-click on the link above
and select “Copy Link”

We are using cookies for the best presentation of our site. Continuing to use this site, you agree with this.