stringtranslate.com

Seguridad basada en el lenguaje

En informática , la seguridad basada en lenguaje ( LBS ) es un conjunto de técnicas que se pueden utilizar para reforzar la seguridad de las aplicaciones a un alto nivel mediante el uso de las propiedades de los lenguajes de programación. Se considera que LBS refuerza la seguridad informática a nivel de aplicación, lo que permite evitar vulnerabilidades que la seguridad tradicional de los sistemas operativos no puede controlar.

Las aplicaciones de software suelen especificarse e implementarse en determinados lenguajes de programación y, para protegerse contra ataques, fallas y errores a los que podría ser vulnerable el código fuente de una aplicación , es necesario contar con seguridad a nivel de aplicación; seguridad que evalúe el comportamiento de las aplicaciones con respecto al lenguaje de programación. Esta área se conoce generalmente como seguridad basada en lenguaje.

Motivación

El uso de grandes sistemas de software, como SCADA , se está dando en todo el mundo [1] y los sistemas informáticos constituyen el núcleo de muchas infraestructuras. La sociedad depende en gran medida de infraestructuras como el agua, la energía, las comunicaciones y el transporte, que a su vez dependen de sistemas informáticos que funcionen en su totalidad. Hay varios ejemplos bien conocidos de casos en los que los sistemas críticos fallan debido a errores o fallas en el software, como cuando la falta de memoria en la computadora provocó que las computadoras del aeropuerto de Los Ángeles fallaran y que cientos de vuelos se retrasaran (30 de abril de 2014). [2] [3]

Tradicionalmente, los mecanismos utilizados para controlar el comportamiento correcto del software se implementan a nivel del sistema operativo. El sistema operativo maneja varias posibles violaciones de seguridad, como violaciones de acceso a memoria, violaciones de desbordamiento de pila, violaciones de control de acceso y muchas otras. Esta es una parte crucial de la seguridad en los sistemas informáticos, sin embargo, al asegurar el comportamiento del software a un nivel más específico, se puede lograr una seguridad aún más fuerte. Dado que muchas propiedades y comportamientos del software se pierden en la compilación, es significativamente más difícil detectar vulnerabilidades en el código de máquina. Al evaluar el código fuente, antes de la compilación, también se puede considerar la teoría y la implementación del lenguaje de programación, y se pueden descubrir más vulnerabilidades.

"Entonces, ¿por qué los desarrolladores siguen cometiendo los mismos errores? En lugar de confiar en la memoria de los programadores, deberíamos esforzarnos por producir herramientas que codifiquen lo que se sabe sobre las vulnerabilidades de seguridad más comunes e integrarlo directamente en el proceso de desarrollo".

— D. Evans y D. Larochelle, 2002

Objetivo de la seguridad basada en el lenguaje

Al utilizar LBS, la seguridad del software se puede aumentar en varias áreas, dependiendo de las técnicas utilizadas. Se pueden detectar y rechazar errores de programación comunes, como permitir desbordamientos de búfer y flujos de información ilegales, en el software utilizado por el consumidor. También es conveniente proporcionar alguna prueba al consumidor sobre las propiedades de seguridad del software, lo que le permite confiar en el software sin tener que recibir el código fuente y comprobar por sí mismo si hay errores.

Un compilador, tomando el código fuente como entrada, realiza varias operaciones específicas del lenguaje sobre el código para traducirlo a código legible por máquina. El análisis léxico , el preprocesamiento , el análisis sintáctico , el análisis semántico , la generación de código y la optimización del código son operaciones que se utilizan habitualmente en los compiladores. Al analizar el código fuente y utilizar la teoría y la implementación del lenguaje, el compilador intentará traducir correctamente el código de alto nivel a código de bajo nivel, preservando el comportamiento del programa.

Ilustrando un compilador certificador

Durante la compilación de programas escritos en un lenguaje de tipo seguro , como Java , el código fuente debe comprobarse correctamente antes de la compilación. Si la comprobación de tipo falla, no se realizará la compilación y será necesario modificar el código fuente. Esto significa que, dado un compilador correcto, cualquier código compilado a partir de un programa fuente comprobado correctamente debería estar libre de errores de asignación no válidos. Esta es una información que puede ser valiosa para el consumidor de código, ya que proporciona cierto grado de garantía de que el programa no se bloqueará debido a algún error específico.

Un objetivo de LBS es garantizar la presencia de determinadas propiedades en el código fuente que correspondan a la política de seguridad del software. La información recopilada durante la compilación se puede utilizar para crear un certificado que se puede proporcionar al consumidor como prueba de seguridad del programa en cuestión. Dicha prueba debe implicar que el consumidor puede confiar en el compilador utilizado por el proveedor y que el certificado, la información sobre el código fuente, se puede verificar.

La figura ilustra cómo se puede establecer la certificación y verificación de código de bajo nivel mediante el uso de un compilador certificador. El proveedor de software obtiene la ventaja de no tener que revelar el código fuente, y el consumidor se queda con la tarea de verificar el certificado, lo que es una tarea fácil en comparación con la evaluación y compilación del código fuente en sí. La verificación del certificado solo requiere una base de código confiable limitada que contenga el compilador y el verificador.

Técnicas

Análisis del programa

Las principales aplicaciones del análisis de programas son la optimización de los mismos (tiempo de ejecución, requisitos de espacio, consumo de energía, etc.) y la corrección de los programas (errores, vulnerabilidades de seguridad, etc.). El análisis de programas se puede aplicar a la compilación ( análisis estático ), al tiempo de ejecución ( análisis dinámico ) o a ambos. En la seguridad basada en lenguajes, el análisis de programas puede proporcionar varias funciones útiles, como: comprobación de tipos (estática y dinámica), monitorización , comprobación de defectos y análisis del flujo de control .

Análisis del flujo de información

El análisis del flujo de información puede describirse como un conjunto de herramientas utilizadas para analizar el control del flujo de información en un programa, con el fin de preservar la confidencialidad y la integridad cuando los mecanismos de control de acceso regulares resultan insuficientes.

"Al disociar el derecho de acceso a la información del derecho a difundirla, el modelo de flujo supera al modelo de matriz de acceso en su capacidad de especificar un flujo de información seguro. Un sistema práctico necesita tanto control de acceso como de flujo para satisfacer todos los requisitos de seguridad".

—D. Denning, 1976

El control de acceso aplica controles sobre el acceso a la información, pero no se preocupa por lo que sucede después. Un ejemplo: un sistema tiene dos usuarios, Alice y Bob. Alice tiene un archivo secret.txt , que solo ella puede leer y editar, y prefiere mantener esta información para sí misma. En el sistema, también existe un archivo public.txt , que todos los usuarios del sistema pueden leer y editar libremente. Ahora supongamos que Alice ha descargado accidentalmente un programa malicioso. Este programa puede acceder al sistema como Alice, evitando el control de acceso en secret.txt . A continuación, el programa malicioso copia el contenido de secret.txt y lo coloca en public.txt , lo que permite que Bob y todos los demás usuarios lo lean. Esto constituye una violación de la política de confidencialidad prevista del sistema.

No interferencia

La no interferencia es una propiedad de los programas que no filtra ni revela información de las variables con una clasificación de seguridad más alta , dependiendo de la entrada de variables con una clasificación de seguridad más baja . Un programa que satisface la no interferencia debe producir la misma salida siempre que se utilice la misma entrada correspondiente en las variables de menor seguridad . Esto debe cumplirse para cada valor posible en la entrada. Esto implica que incluso si las variables de mayor seguridad en el programa tienen valores diferentes de una ejecución a otra, esto no debería ser visible en las variables de menor seguridad .

Un atacante podría intentar ejecutar un programa que no cumpla con los requisitos de no interferencia de forma repetida y sistemática para intentar mapear su comportamiento. Varias iteraciones podrían llevar a la divulgación de variables más altas y permitir que el atacante obtenga información confidencial sobre, por ejemplo, el estado del sistema.

Si un programa satisface o no la no interferencia se puede evaluar durante la compilación asumiendo la presencia de sistemas de tipo de seguridad .

Sistema de tipo de seguridad

Un sistema de tipos de seguridad es un tipo de sistema de tipos que pueden utilizar los desarrolladores de software para comprobar las propiedades de seguridad de su código. En un lenguaje con tipos de seguridad, los tipos de variables y expresiones se relacionan con la política de seguridad de la aplicación, y los programadores pueden especificar la política de seguridad de la aplicación mediante declaraciones de tipos. Los tipos se pueden utilizar para razonar sobre varios tipos de políticas de seguridad, incluidas las políticas de autorización (como control de acceso o capacidades) y la seguridad del flujo de información. Los sistemas de tipos de seguridad se pueden relacionar formalmente con la política de seguridad subyacente, y un sistema de tipos de seguridad es sólido si todos los programas que realizan la comprobación de tipos satisfacen la política en un sentido semántico. Por ejemplo, un sistema de tipos de seguridad para el flujo de información podría imponer la no interferencia, lo que significa que la comprobación de tipos revela si existe alguna violación de la confidencialidad o la integridad en el programa.

Asegurar el código de bajo nivel

Las vulnerabilidades en el código de bajo nivel son errores o fallas que llevan al programa a un estado en el que el lenguaje de programación fuente no define su comportamiento posterior. El comportamiento del programa de bajo nivel dependerá del compilador, el sistema de ejecución o los detalles del sistema operativo. Esto permite que un atacante lleve el programa a un estado indefinido y explote el comportamiento del sistema.

Los ataques más comunes a códigos de bajo nivel inseguros permiten que un atacante realice operaciones de lectura o escritura no autorizadas en direcciones de memoria. Las direcciones de memoria pueden ser aleatorias o elegidas por el atacante.

Uso de lenguajes seguros

Un enfoque para lograr un código de bajo nivel seguro es utilizar lenguajes seguros de alto nivel. Se considera que un lenguaje seguro está completamente definido por el manual de su programador. [4] Cualquier error que pueda conducir a un comportamiento dependiente de la implementación en un lenguaje seguro se detectará en tiempo de compilación o conducirá a un comportamiento de error bien definido en tiempo de ejecución. En Java , si se accede a una matriz fuera de los límites, se lanzará una excepción. Ejemplos de otros lenguajes seguros son C# , Haskell y Scala .

Ejecución defensiva de lenguajes inseguros

Durante la compilación de un lenguaje no seguro, se agregan verificaciones en tiempo de ejecución al código de bajo nivel para detectar comportamientos indefinidos en el nivel de fuente. Un ejemplo es el uso de canarios , que pueden finalizar un programa al descubrir violaciones de límites. Una desventaja de usar verificaciones en tiempo de ejecución, como en la verificación de límites, es que imponen una sobrecarga de rendimiento considerable.

La protección de la memoria , como el uso de una pila o un montón no ejecutables, también puede considerarse como comprobaciones adicionales en tiempo de ejecución. Esto lo utilizan muchos sistemas operativos modernos.

Ejecución aislada de módulos

La idea general es identificar el código sensible de los datos de la aplicación mediante el análisis del código fuente. Una vez hecho esto, los distintos datos se separan y se colocan en diferentes módulos. Si se supone que cada módulo tiene control total sobre la información sensible que contiene, es posible especificar cuándo y cómo debe salir del módulo. Un ejemplo es un módulo criptográfico que puede evitar que las claves salgan del módulo sin cifrar.

Compilación de certificación

Certificar la compilación es la idea de producir un certificado durante la compilación del código fuente, utilizando la información de la semántica del lenguaje de programación de alto nivel. Este certificado debe incluirse junto con el código compilado para proporcionar una forma de prueba al consumidor de que el código fuente se compiló de acuerdo con un determinado conjunto de reglas. El certificado se puede producir de diferentes maneras, por ejemplo, mediante código portador de pruebas (PCC) o lenguaje ensamblador tipado (TAL).

Código portador de pruebas

Los principales aspectos del PCC se pueden resumir en los siguientes pasos: [5]

  1. El proveedor proporciona un programa ejecutable con varias anotaciones producidas por un compilador certificador.
  2. El consumidor proporciona una condición de verificación, basada en una política de seguridad , que se envía al proveedor.
  3. El proveedor ejecuta la condición de verificación en un demostrador de teoremas para producir una prueba para el consumidor de que el programa de hecho satisface la política de seguridad.
  4. Luego, el consumidor ejecuta la prueba en un verificador de pruebas para verificar su validez.

Un ejemplo de un compilador certificador es el compilador Touchstone, que proporciona una prueba formal PCC de seguridad de tipos y memoria para programas implementados en Java.

Lenguaje ensamblador tipificado

TAL es aplicable a lenguajes de programación que hacen uso de un sistema de tipos . Después de la compilación, el código objeto llevará una anotación de tipo que puede ser verificada por un verificador de tipos ordinario. La anotación producida aquí es en muchos aspectos similar a las anotaciones proporcionadas por PCC, con algunas limitaciones. Sin embargo, TAL puede manejar cualquier política de seguridad que pueda ser expresada por las restricciones del sistema de tipos, que pueden incluir seguridad de memoria y flujo de control, entre otros.

Seminarios

Referencias

  1. ^ "¿Podemos aprender de los incidentes de seguridad SCADA?" (PDF) . www.oas.org . enisa.
  2. ^ "Error en el sistema de control de tráfico aéreo" www.computerworld.com . Consultado el 12 de mayo de 2014 .
  3. ^ "Un error de software contribuyó al apagón". www.securityfocus.com . Consultado el 11 de febrero de 2004 .
  4. ^ Pierce, Benjamin C. (2002). Tipos y lenguajes de programación. The MIT Press. ISBN 9780262162098.
  5. ^ Kozen, Dexter (1999). "Seguridad basada en el lenguaje" (PDF) . Universidad de Cornell. {{cite journal}}: Requiere citar revista |journal=( ayuda )

Libros

Lectura adicional