Evitar saturaciones de búfer

Una saturación del búfer es uno de los orígenes más comunes de riesgo de seguridad. Básicamente, un desbordamiento de búfer se produce al tratar una entrada externa no validada como si fueran datos fiables. El acto de copiar estos datos, mediante operaciones como CopyMemory, strcat, strcpy o wcscpy, puede crear resultados imprevistos, lo que permite daños en el sistema. En el mejor de los casos, tu aplicación se abortará con un volcado de memoria, un error de segmentación o una violación de acceso. En el peor de los casos, un atacante puede aprovechar la saturación del búfer introduciendo y ejecutando otro código malintencionado en el proceso. Copiar datos de entrada no activados en un búfer basado en pila es la causa más común de errores que se pueden aprovechar.

Warning

Nunca use funciones de cadena no acotadas (strcpy, strcat, sprintf, gets) en código sensible a la seguridad. Reemplácelas por sus equivalentes enlazados (StringCbCopy, StringCbCat, StringCbPrintf) de la biblioteca de cadenas seguras o use las variantes de sufijo C11 _s (strcpy_s, strcat_s).

Los desbordamientos de búfer pueden producirse de varias maneras. En la lista siguiente se proporciona una breve introducción a algunos tipos de situaciones de saturación de búfer y se ofrecen algunas ideas y recursos que le ayudarán a evitar la creación de nuevos riesgos y mitigar los existentes:

Desbordamientos de búfer estático

Un desbordamiento de búfer estático se produce cuando se escribe en un búfer, declarado en la pila, más cantidad de datos de la que se le asignó para almacenar. Las versiones menos aparentes de este error se producen cuando los datos de entrada de usuario no comprobados se copian directamente en una variable estática, lo que provoca posibles daños en la pila.

Desbordamientos del montón

Las saturaciones del montón, como las saturaciones de búfer estático, pueden provocar daños en la memoria y la pila. Dado que los desbordamientos del montón se producen en la memoria del montón en lugar de en la pila, algunas personas consideran que son menos propensos a causar problemas graves; sin embargo, los desbordamientos del montón requieren verdadero cuidado al programar y pueden dar lugar a riesgos para el sistema con la misma facilidad que los desbordamientos de búfer estático.

Errores de indexación de matriz

Los errores de indexación de matriz también son un origen de saturaciones de memoria. La comprobación cuidadosa de límites y la administración de índices ayudarán a evitar la saturación de este tipo de memoria.

La prevención de saturaciones de búfer consiste principalmente en escribir código correcto. Valide siempre todos los datos de entrada y gestione los fallos de forma controlada cuando sea necesario. Para obtener más información sobre cómo escribir código seguro, consulte los siguientes recursos:

  • Maguire, Steve [1993], Escribir código sólido, ISBN 1-55615-551-4, Microsoft Press, Redmond, Washington.
  • Howard, Michael y LeBlanc, David [2003], Escribir código seguro, 2d ed., ISBN 0-7356-1722-8, Microsoft Press, Redmond, Washington.

Note

Es posible que estos recursos no estén disponibles en algunos idiomas y países.

 

El control seguro de cadenas es un problema de larga duración que sigue siendo solucionado mediante procedimientos de programación recomendados y, a menudo, mediante el uso y la retroajustación de sistemas existentes con funciones seguras y de control de cadenas. Un ejemplo de este conjunto de funciones para el shell de Windows comienza con StringCbCat.

Mitigaciones del compilador y del vinculador

Las versiones modernas del compilador y vinculador de C/C++ de Microsoft proporcionan varias capas de defensa contra saturaciones de búfer. Habilite siempre estas protecciones en las versiones de producción:

Flag propósito
/GS Detección de saturación del búfer de pila (habilitada de forma predeterminada). Inserta cookies de seguridad antes de las direcciones de retorno.
/sdl Habilita comprobaciones de seguridad adicionales, incluido el comportamiento más /GS estricto y la inicialización de variables.
/DYNAMICBASE Aleatorización de la disposición del espacio de direcciones (ASLR). Aleatoriza las direcciones de carga para que la explotación sea más difícil.
/NXCOMPAT Prevención de ejecución de datos (DEP). Marca páginas de memoria como no ejecutables.
/CETCOMPAT Tecnología Intel Control-flow Enforcement (CET) para pilas sombra protegidas por hardware.
/guard:cf Protección de flujo de control (CFG). Valida los destinos de llamadas indirectas en tiempo de ejecución.

Importante

Compile con /sdl y /GS como mínimo para todo el código nuevo. En el caso de las aplicaciones críticas para la seguridad, habilite y vincule /guard:cf con /CETCOMPAT cuando tenga como destino hardware que admita CET.

Herramientas de análisis en tiempo de ejecución

Use estas herramientas durante el desarrollo y las pruebas para detectar problemas de seguridad de memoria antes de llegar a producción:

  • AddressSanitizer (ASan): Compile con /fsanitize=address para detectar desbordamientos de búfer, use-after-free y otros errores de memoria en tiempo de ejecución. Disponible en Visual Studio 2019 16.9 y versiones posteriores.
  • Comprobador de aplicaciones: Detecta daños en el montón, controla el uso incorrecto y otros errores de programación comunes.
  • Análisis estático (/analyze): el analizador estático integrado detecta saturaciones de búfer, variables sin inicializar y otros problemas en tiempo de compilación.