visual studio programacion optimizar optimizacion intermedio codigo c++ security optimization memory compiler-construction

c++ - studio - optimizacion de codigo intermedio



¿Cómo asegurar que las optimizaciones del compilador no presenten un riesgo de seguridad? (6)

¿Por qué no inhabilitas la optimización para el código en cuestión?

#pragma optimize( "", off ) // Code, not to optimize goes here #pragma optimize( "", on )

Esta muestra de #pragma optimize es específica de MSVC, pero otros compiladores también la admiten.

Tengo que escribir un servicio de Windows que maneje en algún momento datos confidenciales (como códigos PIN, contraseñas, etc.). Esas informaciones son necesarias por muy poco tiempo: por lo general, se envían casi de inmediato a un lector de tarjetas inteligentes.

Consideremos este pedazo de código:

{ std::string password = getPassword(); // Get the password from the user writePasswordToSmartCard(password); // Okay, here we don''t need password anymore. // We set it all to ''/0'' so it doesn''t stay in memory. std::fill(password.begin(), password.end(), ''/0''); }

Ahora mi preocupación es acerca de las optimizaciones del compilador. Aquí el compilador puede detectar que la contraseña está a punto de borrarse y que cambiar su valor en este punto es inútil y simplemente eliminar la llamada.

No espero que mi compilador se preocupe por el valor de la memoria futura sin referencia.

¿Son mis preocupaciones legítimas? ¿Cómo puedo estar seguro de que ese código no se optimizará?


Declare la contraseña volátil para evitar que el compilador haga suposiciones sobre la eliminación de lecturas o escrituras explícitas.

volatile std::string password = getPassword(); // Get the password from the user


En esta instancia específica, me sorprendería mucho si el compilador puede optimizar una invocación de método que claramente podría tener efectos secundarios. ¿O está std :: fill en línea para que el compilador pueda ver la implementación? (No soy un programador de C ++).

Habiendo dicho eso, este tipo de cosas puede ser una preocupación en general. Pero debes pensar en lo fácil que es explotar. Para leer la memoria de otro proceso, un atacante necesitaría algún nivel de acceso de administrador (de lo contrario, ¿por qué está usando ese sistema operativo?). Si la máquina está comprometida a ese nivel, ya ha perdido.


Es problemático, pero por otra razón. ¿Quién dijo que std::string password = getPassword(); no deja otra copia en la memoria? (Probablemente necesite escribir una clase de asignador "seguro" para esto que borre la memoria de "destrucción" o "desasignar")

En su tranquilidad de código, puede evitar la optimización al obtener un puntero volátil a los datos de la cadena (no sé si puede hacerlo de manera estándar) y luego pasar los datos a cero.


Sí, sus preocupaciones son legítimas. SecureZeroMemory() utilizar funciones específicamente diseñadas como SecureZeroMemory() para evitar que las optimizaciones modifiquen el comportamiento de su código.

No olvide que la clase de cadena debería haber sido diseñada específicamente para manejar contraseñas. Por ejemplo, si la clase reasigna el búfer para contener una cadena más larga, debe borrar el búfer antes de volver a asignarlo al asignador de memoria. No estoy seguro, pero es probable que std::string no haga eso (al menos por defecto). Usar una clase inadecuada de manejo de cadenas hace que todas tus preocupaciones no tengan ningún valor: tendrás la contraseña copiada en toda la memoria del programa antes de que lo sepas.


No use std::string para contraseñas, ya que no pone a cero su memoria cuando realiza reasignaciones o destrucción; en su lugar, diseñe su propia clase ConfidentialString . Al diseñar esa clase, es posible que desee aprovechar CryptProtectMemory ... y tenga mucho, mucho cuidado cuando necesite usar la versión descifrada, especialmente cuando llame a un código externo.