Seminario web destacado: Presentación de la prueba CT de Parasoft C/C++ para pruebas continuas y excelencia en el cumplimiento | Vea ahora

¿Qué es CERT C++?

Foto de cabeza de Miroslaw Zielinski, director de gestión de productos de Parasoft
27 de Octubre de 2023
7 min leer

El desarrollo de software incluye la seguridad como componente clave y CERT C++ es una de las mejores opciones si desea seguir los estándares de codificación de seguridad adecuados. Siga leyendo para ver por qué no debería ignorar CERT C++.

La seguridad se está convirtiendo en un nuevo mantra de los equipos de desarrollo de software, especialmente para los responsables de la seguridad o del software de misión crítica. En el pasado, la seguridad era a menudo una característica que los equipos intentaban agregar a los sistemas ya construidos al final del ciclo de desarrollo, frecuentemente girando en círculos viciosos de pruebas y correcciones. Hoy sabemos que la seguridad es una disciplina de ingeniería sólida respaldada por múltiples programas y estándares de investigación.

Si desea que su sistema sea seguro desde el diseño, debe comenzar desde el principio del proceso de desarrollo y asegurarse de que cada línea de código creado siga las mejores prácticas de seguridad. Para los equipos que desarrollan en C++, una de las mejores opciones en las que confiar es Estándar de codificación segura CERT. La prueba Parasoft C/C++ es la única herramienta que admite integralmente este estándar. Pruebas de seguridad de Parasoft y cumplimiento es la solución más completa del mercado para código C y C++.

¿Qué es CERT C++?

El estándar SEI CERT C++, publicado por primera vez en 2006, es una extensión del estándar CERT C. Ambos provienen del Equipo de respuesta de emergencia informática (CERT) del Instituto de Ingeniería de Software de la Universidad Carnegie Mellon.

El objetivo principal de CERT C++ es promover prácticas de codificación seguras proporcionando a los desarrolladores un subconjunto más seguro del lenguaje C++ que evite las debilidades del software que conducen a vulnerabilidades de seguridad. Además, estas reglas y prácticas de codificación ayudan a mejorar la confiabilidad y la capacidad de mantenimiento del software. El estándar CERT C++ se utiliza a menudo como estándar de codificación para ayudar a las organizaciones a cumplir los objetivos de cumplimiento en materia de seguridad y protección.

El papel de "cstdint" en CERT C++

Antes de C++ 11, la ausencia o separación de la estandarización para los tipos de enteros en C++ hizo que algunos desarrolladores usaran el lenguaje C. archivo para definiciones de tipos. Esto provocó problemas de compatibilidad en la codificación, la construcción de programas portátiles y la integración con funciones de C++. en C++ es una herramienta valiosa porque ofrece tipos enteros de tamaño preciso, mejorando la portabilidad del código y disminuyendo las posibilidades de problemas de seguridad relacionados con los números enteros. No obstante, es importante tener en cuenta que el simple hecho de usar no elimina automáticamente las vulnerabilidades, como desbordamientos de enteros, confusión de tipos, desbordamientos de búfer, vulnerabilidades de cadenas de formato y problemas de big/little endian que pueden provocar vulnerabilidades en la interpretación de datos.

Para mantener una base de código segura, debe cumplir con las mejores prácticas de codificación CERT C++ establecidas, como verificar minuciosamente los límites, elegir los tipos de números enteros correctos y validar los datos de entrada. Estas precauciones son cruciales para reducir la probabilidad de problemas de seguridad.

Expresiones primarias en C++

Las expresiones primarias en C++ son los componentes básicos del lenguaje y abarcan variables, literales, llamadas a funciones, etc. En el contexto de la codificación segura con CERT C++, las expresiones primarias son un foco de atención, ya que estas operaciones pueden ser fuentes potenciales de vulnerabilidades. El estándar de codificación proporciona reglas y directrices para utilizar expresiones primarias de forma segura, como por ejemplo:

  • Evitar variables no inicializadas para evitar comportamientos indefinidos.
  • Usar tipos de datos apropiados y conversiones de tipos seguros para evitar vulnerabilidades relacionadas con los datos.
  • Asegúrese de que las llamadas a funciones se realicen con un manejo de errores y una validación de parámetros adecuados para evitar problemas como desbordamientos del búfer.
  • Gestionar adecuadamente los punteros y referencias para prevenir vulnerabilidades relacionadas con la memoria.

Directrices de codificación CERT C++

El estándar SEI CERT C++ introduce una colección de reglas para hacer cumplir prácticas de codificación seguras y eliminar construcciones de código vulnerables. El estándar está organizado en 11 capítulos que contienen reglas en áreas temáticas específicas. A diferencia de CERT C, el estándar de codificación CERT C++ solo tiene reglas y no recomendaciones. Están pendientes de mayor revisión y desarrollo.

SEI CERT C++ se basa en el estándar CERT C y abarca el subconjunto de reglas CERT C que se aplican a C++. En este momento (tenga en cuenta que CERT es un estándar de vida), hay 143 reglas CERT C++ y 136 reglas heredadas de CERT C. En el siguiente cuadro se presenta una descripción general del estándar CERT C++, seguido de una lista de sus capítulos.

Gráfico que muestra el número de reglas CERT C++ por capítulo, tanto las reglas CERT C++ originales como las heredadas de CERT C.

Regla 01. Declaraciones e Inicialización (DCL)

Proporciona reglas y pautas para declarar e inicializar variables y objetos de una manera que garantice un estado inicializado válido y evite errores comunes.

Regla 02. Expresiones (EXP)

Cubre reglas relacionadas con las expresiones, enfatizando la necesidad de manejar adecuadamente los resultados de las expresiones, evitando efectos secundarios no deseados y garantizando que las expresiones estén bien formadas y sean fáciles de mantener.

Regla 03. Números enteros (INT)

Se centra en reglas para manejar números enteros con énfasis en prevenir desbordamientos y subdesbordamientos de enteros y otros problemas relacionados con las operaciones con enteros.

Regla 04. Contenedores (CTR)

Este capítulo trata sobre las reglas para el uso de contenedores de biblioteca estándar de C++, como vectores y matrices, promoviendo una gestión y un uso seguros y eficientes de los contenedores.

Regla 05. Caracteres y Cadenas (STR)

Proporciona pautas para el manejo adecuado de caracteres y cadenas, incluida la garantía de una terminación nula adecuada y la prevención de vulnerabilidades comunes relacionadas con las cadenas.

Regla 06. Gestión de Memoria (MEM)

Se centra en reglas para una gestión eficaz de la memoria, incluida la asignación y desasignación dinámica de la memoria, para evitar pérdidas de memoria y otros problemas relacionados con la memoria.

Regla 07. Entrada Salida (FIO)

Cubre reglas para operaciones seguras de entrada y salida, destacando la importancia de validar los datos de entrada y manejar las operaciones de archivos de forma segura.

Regla 08. Excepciones y Manejo de Errores (ERR)

Aborda reglas para administrar excepciones y errores, enfatizando las mejores prácticas para manejar excepciones y errores en código C++.

Regla 09. Programación Orientada a Objetos (POO)

Proporciona directrices para la programación orientada a objetos, incluidas recomendaciones para el diseño de clases, la herencia y el polimorfismo.

Regla 10. Concurrencia (CON)

Se centra en reglas relacionadas con la programación concurrente, abordando problemas y mejores prácticas para subprocesos múltiples y paralelismo.

Regla 49. Varios (MSC)

Contiene reglas diversas que no encajan perfectamente en las otras categorías pero que son importantes para escritura segura y confiable Código C ++.

Como ilustra el cuadro anterior, cada una de estas reglas de nivel superior contiene reglas más específicas, algunas de las cuales son específicas de C++ y otras de CERT C también se aplican.

Parasoft C / C ++test tiene soporte total para las pautas de codificación CERT C++. La configuración de prueba (“Reglas SEI CERT C++”) habilita todos los verificadores del conjunto de reglas CERT C++ original y aquellos de CERT C que son aplicables para C++, que es precisamente como lo define CERT para garantizar la seguridad de su código base de C++. Las organizaciones que desarrollan con C y C++, incluidos los equipos que planean cambiar a C++, pueden confiar en una única solución con informes consistentes.

Los equipos también se benefician de informes de cumplimiento dedicados para CERT C y C++, para construir un proceso de cumplimiento sostenible. Con las extensiones de informes, los usuarios pueden obtener una vista dinámica del proceso de cumplimiento y revisar las infracciones priorizadas según el marco de evaluación de riesgos del CERT.

El CERT atribuye cada infracción con una puntuación por los siguientes tres factores:

  • Gravedad
  • Probabilidad
  • Costo de remediación

La prioridad se calcula como producto de estos tres factores y se divide en niveles: L1, L2 y L3. L1 representa violaciones de alta gravedad con alta probabilidad y bajo costo de remediación. Estos son los que los equipos están más interesados ​​en solucionar, ya que indican problemas graves que no son complicados de remediar. El uso del marco de puntuación del CERT proporciona una gran ayuda para centrar los esfuerzos y permitir que los equipos aprovechen al máximo los presupuestos de tiempo.

Además de los widgets, los exploradores de infracciones y un marco de puntuación de riesgos que le ayuda a orientarse rápidamente en el avance del proceso de cumplimiento, el marco de informes de Parasoft también le ahorra tiempo al generar automáticamente informes de cumplimiento que son adecuados para auditorías de código. Esta es una funcionalidad interesante si su organización es más formal con el proceso de desarrollo.

Benefíciese de CERT C++

C++ es un gran lenguaje. Si bien tiene muchas características del lenguaje OO moderno, lo que le permite diseñar sistemas complejos con patrones de diseño OO avanzados, también ofrece una gran eficiencia porque le permite acceder a la memoria directamente a través de punteros sin verificar si este acceso es correcto.

Por supuesto, estos beneficios tienen un precio. Con C++, incluso los desarrolladores de software con mucha experiencia pueden crear código vulnerable, generalmente debido a problemas de administración y acceso a la memoria. Los desbordamientos de búfer, el uso de referencias colgantes y los desbordamientos de enteros pueden provocar un comportamiento indefinido, que puede explotarse de múltiples maneras.

Un ejemplo es la inyección de arco. Un atacante puede intentar transferir maliciosamente el control al código existente en la memoria del proceso de forma distinta a la prevista.

Otro ejemplo es la inyección de código, que consiste en inyectar código en la memoria del sistema en ejecución para obtener control sobre un sistema con privilegios del programa comprometido, o peor aún, con un nivel de acceso al kernel. Una vez que se toma ese control, las pérdidas pueden ser devastadoras.

¿Cómo podemos evitar que los atacantes penetren en nuestro sistema? No es posible tomar una base de código existente e intentar adivinar todas las posibles violaciones de seguridad. La mejor opción disponible actualmente para los programadores de C/C++ es, en primer lugar, crear código que esté libre de ciertas construcciones que han demostrado ser una fuente de violaciones de seguridad.

Veamos una ilustración sencilla. El siguiente fragmento de código fuente se ha tomado directamente del estándar CERT C++ (regla EXP61-CPP).

auto g() {
int i = 12;
return [&] {
i = 100; // Problem
return i;
};
}

void f() {
int j = g()();
}

En este ejemplo, la función g() devuelve una lambda, que captura implícitamente la variable local automática "i" por referencia. Este código mal escrito tiene al menos una vulnerabilidad de seguridad cuando se devuelve lambda desde la llamada g(). La referencia que capturó se referirá a una variable cuya vida útil ha finalizado (la función g desapareció).

Como resultado, cuando la lambda se ejecuta en f(), el uso de la referencia colgante en la lambda afecta el comportamiento indefinido. Este comportamiento indefinido puede explotarse para obtener control sobre el programa. La memoria que estaba ocupada por "i" durante la vida útil de la función g ya está liberada, y esta porción de la pila probablemente ya se haya reutilizado para otros propósitos, posiblemente una dirección de retorno de la llamada a la función, que cuando se sobrescribe se puede usar para ejecutar código arbitrario.

Esta vulnerabilidad específica es detectable por la regla, EXP61-CPP Un objeto lambda no debe sobrevivir a ninguno de sus objetos capturados de referencia. El código fuente que sea compatible con CERT C++ no debería contener ningún caso de este problema.

CERT C++ incluye muchas más reglas que pueden detectar problemas potenciales y le ayudarán a promover prácticas de codificación seguras. El uso de CERT C++ ofrece importantes beneficios a los desarrolladores de software.

  • Mejora la seguridad. Cumplir con el estándar da como resultado un código más seguro, lo que reduce las vulnerabilidades y el riesgo de violaciones de seguridad.
  • Mejora la confiabilidad. Promueve mejores prácticas que mejoran la confiabilidad y solidez del código, reduciendo la probabilidad de defectos y fallas.
  • Mantenibilidad. Las reglas fomentan un código que sea más fácil de entender y mantener, simplificando los esfuerzos continuos de desarrollo y mantenimiento.
  • Conformidad. El estándar ayuda a las organizaciones y desarrolladores a cumplir con los estándares, regulaciones y requisitos específicos de la industria de seguridad.
  • Reduce la depuración y las pruebas. Al evitar los errores comunes de codificación, los desarrolladores pueden dedicar menos tiempo a depurar y probar y más tiempo al desarrollo productivo.
  • Simultaneidad más segura. El estándar incluye pautas para la programación concurrente (multiproceso y multiproceso) segura, lo que reduce el riesgo de condiciones de carrera y problemas relacionados con subprocesos.
  • Conciencia de seguridad. Los desarrolladores se vuelven más conscientes de la seguridad y aprenden a identificar y mitigar de manera proactiva los riesgos de seguridad en su código.

Las pautas de codificación de seguridad, cuando se usan de manera consistente, pueden ayudar a fortalecer su código fuente y son la estrategia más efectiva para garantizar la seguridad general del sistema. Hoy en día, es realmente difícil encontrar una justificación para no seguir un estándar de codificación de seguridad como CERT C++.

Cómo acelerar el cumplimiento de MISRA C y SEI CERT C