La verificación formal no garantiza un sistema seguro. Nada garantiza un sistema seguro. Lo que puede hacer la verificación formal es proporcionar una seguridad muy alta de que algunas partes del sistema son seguras.
La verificación formal proporciona una prueba matemática de que, bajo ciertas suposiciones, un modelo del sistema tiene ciertas propiedades. Por lo tanto, si parte del sistema se ha verificado formalmente, aún quedan varias condiciones para que el sistema sea seguro:
- ¿Se cumplen los supuestos subyacentes a la verificación?
- ¿El sistema coincide con el modelo que se ha verificado?
- ¿Es correcta la prueba proporcionada por el sistema de verificación?
- ¿Son las propiedades probadas suficientes para garantizar la seguridad del sistema?
El alcance de la verificación formal puede variar mucho. Por ejemplo, desbordamientos de búfer , un tipo común de vulnerabilidad, puede detectarse con bastante facilidad: la mayoría de los idiomas son más altos que C o C ++ garantizan la ausencia de desbordamientos de búfer en el programa compilado. No obstante, puede suceder que el compilador permita que pase un código dañado, aunque los errores del compilador son mucho más raros que los errores de programa, no son imposibles. Sin embargo, los desbordamientos de búfer son de un solo tipo; La seguridad de la mayoría de los sistemas depende de mucho más que saber que no hay desbordamientos de búfer. (Lectura relacionada: ¿Por qué las computadoras no comprueban si hay contenido de memoria en algún espacio de memoria? )
Para ilustrar las limitaciones anteriores, permítame tomar un ejemplo concreto. Algunas tarjetas inteligentes ejecutan una Java Tarjeta de la máquina virtual, y ejecute solo el bytecode que ha sido verificado . El verificador de bytecode, en principio, garantiza que el código no puede mirar o sobresalir fuera de su espacio de memoria asignado. Esto evita algunas vulnerabilidades pero no todas:
- La verificación solo garantiza sus propiedades si el intérprete de bytecode se comporta de acuerdo con su especificación. Además, si el hardware no ejecuta el intérprete correctamente, todas las apuestas están desactivadas (por ejemplo, una forma de atacar a una tarjeta inteligente es causar una falla de energía que hace que se omitan algunas instrucciones).
- Si hay un error que permite cargar el código sin pasar por el verificador, es posible que el código de la tarjeta no tenga las propiedades garantizadas por la verificación.
- El propio verificador puede tener errores y permitir que se cargue un código incorrecto.
- Incluso si el código de las aplicaciones en la tarjeta no accede directamente a la memoria de otras aplicaciones, aún puede espiarlas o perturbarlas de otras maneras. Por ejemplo, puede explotar un canal lateral como el tiempo para deducir las propiedades de otro código que se ejecuta en el mismo dispositivo.
Además, la seguridad del sistema puede depender de otras cosas además del aislamiento entre las aplicaciones en la tarjeta. Por ejemplo, el sistema de autenticación puede permitir que un atacante tome el control de la tarjeta, puede haber una vulnerabilidad a nivel de protocolo que le permita interrumpir las comunicaciones, etc.
En un sistema de alta seguridad, la verificación formal puede ayudar de dos maneras:
- Comprobando que el código coincide con su especificación. Esto requiere un modelo formal del entorno de ejecución (hardware, compilador o intérprete, biblioteca estándar, ...) y mucho trabajo.
- Probando que la especificación tiene ciertas propiedades deseables. Esto requiere una formalización de la especificación, una elección juiciosa de propiedades y mucho trabajo.
Los Criterios comunes para las evaluaciones de seguridad definen varios niveles de seguridad . Solo el nivel de seguridad más alto (EAL7) requiere una verificación formal. Este no es el único requisito: la verificación formal no excluye la evaluación de otros aspectos del sistema, incluida la documentación, las pruebas de penetración, etc.