Compartir a través de


Procedimientos de seguridad recomendados en el desarrollo de juegos

En este artículo se describen los procedimientos recomendados para usarlos en el desarrollo de juegos.

Introducción

Cada vez más personas juegan a juegos en línea y con contenidos creados por los usuarios. Esto, combinado con la creciente seguridad del sistema operativo Microsoft Windows, significa que los juegos son un objetivo cada vez más tentador que los atacantes pueden aprovechar. Los desarrolladores de juegos deberían hacer especial hincapié en asegurarse de que los juegos que lanzan no crean nuevos agujeros de seguridad que puedan aprovechar los atacantes. Los desarrolladores de juegos tienen la responsabilidad y el interés de ayudar a evitar que los equipos de sus clientes sean pirateados por datos maliciosos de la red, modificaciones de los usuarios o manipulaciones. Si se aprovecha una vulnerabilidad, podría dar lugar a la pérdida de clientes o dinero. En este artículo se describen y se explican algunos métodos y herramientas comunes para aumentar la seguridad del código sin inflar demasiado el tiempo de desarrollo.

Los tres errores más comunes que comete un equipo de desarrollo al publicar un producto son:

  • Requerir privilegios de administrador. Los juegos no deben requerir privilegios administrativos. Para obtener más información, consulte Control de cuentas de usuario para desarrolladores de juegos.
  • No usar la protección automatizada. Por lo general, los desarrolladores no usan /GS, /SAFESEH o /NX. El uso de estas marcas de compilación o vínculo puede detectar o eliminar muchos agujeros de seguridad básicos sin aumentar significativamente la carga de trabajo. Estas marcas se describen más adelante en este artículo.
  • Usar API prohibidas. Hay muchas API (strcpy, strncpy, etc.) que son propensas a errores del programador y generan fácilmente agujeros de seguridad. Los desarrolladores deben reemplazar estas API por las versiones seguras. Visual Studio 2005 incluye una herramienta para analizar archivos binarios que pueden comprobar automáticamente los archivos de objeto para ver las referencias a las API no seguras. Para obtener más información sobre qué hacer con la información generada con esta herramienta, consulte Repeler los ataques a código con las bibliotecas C y C++ seguras de Visual Studio 2005 de Martyn Lovell. Además, puede obtener el archivo de encabezado banned.h que puede ayudarle a quitar funciones prohibidas del código (consulte Herramientas de seguridad gratuitas de Microsoft: banned.h).

Cada uno de los errores enumerados no solo es común, sino que se puede corregir fácilmente sin cambios significativos en la carga de trabajo de desarrollo, los estándares de codificación o la funcionalidad.

Ejemplos de código no seguro

A continuación se muestra un ejemplo sencillo de todo lo que se necesita para permitir que un atacante realice un ataque de saturación del búfer:

void GetPlayerName(char *pDatafromNet)
{
    char playername[256]; 
    strncpy(playername, pDatafromNet, strlen(pDatafromNet));

    // ...
}

En la superficie, este código parece correcto: al fin y al cabo llama a una función segura. Los datos de la red se copian en un búfer de 256 bytes. La función strncpy se basa en buscar un terminador NULL en la cadena de origen o está limitada por el recuento de búferes proporcionado. El problema es que el tamaño del búfer es incorrecto. Si los datos de la red no se validan o el tamaño del búfer es incorrecto (como en este ejemplo), un atacante podría simplemente proporcionar un búfer grande para sobrescribir los datos de la pila, después de que finalice el búfer, con los datos del paquete de red. Esto permitiría al atacante ejecutar código arbitrario sobrescribiendo el puntero de instrucción y cambiando la dirección de retorno. La lección más básica de este ejemplo es no confiar nunca en la entrada hasta que se haya comprobado.

Incluso si los datos no proceden de la red inicialmente, sigue existiendo un riesgo potencial. El desarrollo moderno de juegos requiere que muchas personas diseñen, desarrollen y prueben la misma base de código. No hay forma de saber cómo se llamará a la función en el futuro. ¿Siempre se pregunta de dónde proceden los datos y qué podría controlar un atacante? Aunque los ataques basados en red son los más comunes, no son los únicos métodos para crear agujeros de seguridad. ¿Podría un atacante crear un mod o editar un archivo guardado de forma que abriera un agujero de seguridad? ¿Qué ocurre con los archivos de imagen y sonido proporcionados por el usuario? Las versiones malintencionadas de estos archivos podrían publicarse en Internet y crear riesgos de seguridad peligrosos para sus clientes.

Además, use strsafe.h o Safe CRT en lugar de strncpy para corregir el ejemplo. CRT seguro es una revisión de seguridad completa del entorno de ejecución de C y viene con parte de Visual Studio 2005. Puede encontrar más información sobre CRT seguro en Mejoras de seguridad en CRT por Michael Howard.

Formas de mejorar la seguridad

Hay varias maneras de mejorar la seguridad en el ciclo de desarrollo. Estas son algunas de las mejores maneras:

Documentación sobre la seguridad

El libro Writing Secure Code, segunda edición de Michael Howard y David LeBlanc, proporciona una explicación detallada y clara de las estrategias y métodos de prevención de ataques y mitigación de vulnerabilidades de seguridad. A partir de los métodos de diseño de la seguridad en una versión de las técnicas para proteger las aplicaciones de red, el libro trata todos los aspectos que un desarrollador de juegos necesita para ayudar a protegerse, sus productos y sus clientes de atacantes. El libro se puede usar para infundir una cultura de seguridad en un estudio de desarrollo. No piense solo en la seguridad del código como problema del desarrollador o en el problema de un evaluador. Piense en la seguridad como algo que todo el equipo (desde el administrador de programas hasta el diseñador, pasando por el desarrollador y el evaluador) debe pensar cuando trabaja en un proyecto. Cuantos más ojos participen en el proceso de revisión, mayores serán las posibilidades de detectar un agujero de seguridad antes de su publicación.

Writing Secure Code, segunda edición se puede encontrar en Microsoft Press Store y se puede encontrar información de seguridad más general en Fending Off Future Attacks by Reducing Attack Surface de Michael Howard.

Michael Howard, David LeBlanc y John Viega han escrito otro libro sobre el tema que cubre todos los sistemas operativos y lenguajes de programación comunes, titulado, 19 Deadly Sins of Software Security.

Las presentaciones de seguridad centradas en los juegos se pueden encontrar en la página de descarga de presentaciones para desarrolladores de Microsoft XNA.

Análisis de modelado de amenazas

Un análisis de modelado de amenazas es una buena manera de evaluar la seguridad del sistema, no en un lenguaje específico o mediante una herramienta, sino en un método amplio y de un extremo a otro que se puede realizar en algunas reuniones. Cuando se implementa correctamente, un modelo de subprocesos puede identificar todos los puntos fuertes y débiles de un sistema, sin agregar una carga de trabajo significativa ni tiempo de reunión al proyecto. El método de modelado de amenazas también hace hincapié en la idea de evaluar la seguridad del sistema antes y durante el proceso de desarrollo para ayudar a garantizar que se realiza una evaluación completa mientras se centra en las características más arriesgadas. Se puede considerar como generador de perfiles para la seguridad. Al no basarse en un lenguaje concreto ni depender de una herramienta específica, el modelado de amenazas puede utilizarse en cualquier estudio de desarrollo que trabaje en cualquier proyecto de cualquier género. El modelado de amenazas también es un excelente método para reforzar la idea de que la seguridad es responsabilidad de todos y no el problema de otra persona.

Al modelar amenazas, preste especial atención a:

  • Orígenes de datos UDP
  • Orígenes de datos que no requieren autenticación
  • Orígenes de datos que se sondean con frecuencia y normalmente como parte de la recopilación de información a gran escala
  • Cualquier capacidad de un cliente para enviar datos directamente a otros clientes

Estas son las áreas que tienen un buen potencial para las debilidades de seguridad.

Puede encontrar más información sobre el modelado de amenazas en Threat Modeling y en el libro Threat Modeling de Frank Swiderski y Window Snyder.

Prevención de ejecución de datos (/NX)

Una herramienta reciente para mitigar varias vulnerabilidades de seguridad es la prevención de ejecución de datos (DEP). Si incluye el modificador /NX en el comando de compilación, Visual Studio marcará las páginas de memoria con marcas que indican si el código tiene derecho a ejecutarse o no. Cualquier programa que intente ejecutarse en una página de memoria no marcada con el permiso EXECUTE provocará una terminación forzada del programa. La prevención se aplica en el nivel de procesador y afectará a los desarrolladores que usan código automodificar o compiladores nativos del lenguaje JIT. Actualmente, solo los procesadores Athlon64 y Opteron de AMD e Intel Itanium y los procesadores Pentium 4 más recientes admiten la prevención de ejecución, pero se espera que todos los procesadores de 32 y 64 bits admitan la prevención de ejecución en el futuro. (Un esquema de protección de copia usado por un desarrollador puede verse afectado por la prevención de ejecución, pero Microsoft ha estado trabajando con proveedores de protección de copia para minimizar el impacto). Se recomienda usar DEP.

Para obtener más información sobre DEP, consulte Prevención de ejecución de datos.

La comprobación de seguridad del búfer (/GS) y la imagen tienen controladores de excepciones seguros (/SAFESEH)

La comprobación de seguridad del búfer, especificada por la marca del compilador /GS, e Imagen tiene controladores de excepciones seguros, especificados por la marca del enlazador /SAFESEH (que se implementa primero en Visual Studio .NET 2003), puede hacer que el trabajo del desarrollador de proteger el código sea un poco más fácil.

El uso de la marca /GS hace que el compilador cree una comprobación de algunas formas de saturaciones de búfer basadas en pila que se podrían aprovechar para sobrescribir la dirección de retorno de una función. El uso de /GS no detectará cada saturación de búfer potencial y no debe considerarse una tecnología de captura, sino una buena tecnología de defensa en profundidad.

El uso de la marca /SAFESEH indicará al enlazador que solo genere un archivo ejecutable o DLL si también puede generar una tabla de los controladores de excepciones seguros del archivo ejecutable o DLL. El control seguro de excepciones estructuradas (SafeSEH) elimina el control de excepciones como destino de ataques de saturación del búfer asegurándose de que, antes de que se envíe una excepción, el controlador de excepciones se registra en la tabla de funciones ubicada dentro del archivo de imagen. Estas ventajas de protección están habilitadas con Windows XP SP2, Windows Server 2003, Windows Vista y Windows 7. También para que /SAFESEH funcione correctamente, debe usarse en un método todo o nada. Todas las bibliotecas que contienen código enlazado a un archivo ejecutable o DLL deben compilarse con /SAFESEH o no se generará la tabla.

Para obtener más información, consulte Comprobación de seguridad del búfer (/GS) e Imagen tiene controladores de excepciones seguros (/SAFESEH).

Consulte también información sobre la marca /SDL de Microsoft Visual Studio 2012 y las mejoras en la marca /GS de Visual Studio 2012.

PREfast

PREfast es una herramienta gratuita que ofrece Microsoft que se encarga de analizar las rutas de ejecución en C o C++ compilados para detectar errores en tiempo de ejecución. PREfast funciona operando en todas las rutas de ejecución de todas las funciones y evaluando cada ruta en busca de problemas. Aunque esta herramienta se usaba para desarrollar controladores y otro código de kernel, puede ayudar a los desarrolladores de juegos a ahorrar tiempo eliminando algunos errores que son difíciles de encontrar o que el compilador ignora. El uso de PREfast es una excelente manera de reducir la carga de trabajo y centrar los esfuerzos del equipo de desarrollo y del equipo de prueba. PREfast está disponible en Visual Studio Team Suite y Visual Studio Team Edition para desarrolladores de software como análisis de código, habilitado por el modificador del compilador /analyze. (Esta opción también está disponible en la versión gratuita del compilador que se incluye con el Kit de desarrollo de software de Windows).

Nota:

Visual Studio 2012 admite /analyze en todas las ediciones. Para obtener más información sobre la disponibilidad del análisis de código en todas las ediciones de Visual Studio, consulte Novedades en análisis de código.

 

Mediante el uso de anotaciones de encabezado (especialmente para argumentos de puntero de búfer), PREfast puede exponer problemas adicionales, como errores de sobrescritura de memoria, un origen común de bloqueos y posibles vulnerabilidades de seguridad. Esto se hace mediante el lenguaje de anotación estándar (SAL), que es una forma de marcado para prototipos de función de C/C++ que proporcionan información adicional sobre la semántica del argumento de puntero esperado y la correlación con parámetros de longitud, tamaños de búfer declarados, etc. Todos los encabezados de los sistemas operativos Windows se anotan y la adición de marcado SAL en encabezados de API públicas en sus propias bibliotecas permite a PREfast realizar comprobaciones más detalladas y agresivas en el código de cliente para estas API. Para obtener una introducción a SAL y vínculos a más información, consulte la entrada de blog de Michael Howard, "A Brief Introduction to the Standard Annotation Language (SAL)".

Comprobador de aplicaciones para Windows

El Comprobador de aplicaciones de Windows o AppVerifier puede ayudar a los evaluadores proporcionando varias funciones en una herramienta. AppVerifier es una herramienta desarrollada para hacer que los errores de programación comunes sean más fáciles de probar. AppVerifier puede comprobar los parámetros que se pasan en las llamadas a las API, insertar entradas erróneas para comprobar el sistema de control de errores y registrar los cambios en el registro y el sistema de archivos. AppVerifier también puede detectar saturaciones de búfer en el montón, comprobar que se ha definido correctamente una lista de control de acceso (ACL) y aplicar el uso seguro de API de sockets. Aunque no es exhaustiva, AppVerifier puede ser una herramienta en el cuadro de herramientas del evaluador para ayudar a que un estudio de desarrollo publique un producto de calidad.

Para obtener más información sobre Application Verifier, consulte Application Verifier y Uso de Application Verifier en el ciclo de vida de desarrollo de software.

Pruebas de vulnerabilidad ante datos aleatorios o inesperados

Las pruebas aproximadas son un método semiautomático de pruebas que pueden mejorar las metodologías de pruebas actuales. La idea central detrás de las pruebas aproximadas es realizar una evaluación completa de todas las entradas mediante la entrada de datos aleatorios para ver qué se rompe; esto incluye todos los datos de red, mods y juegos guardados, etc. Las pruebas aproximadas son bastante fáciles de hacer. Simplemente modifique archivos o datos de red bien formados insertando bytes aleatorios, girando bytes adyacentes o negando valores numéricos. 0xff, 0xffff, 0xffffffff, 0x00, 0x0000, 0x00000000 y 0x80000000 son valores que son buenos al exponer agujeros de seguridad mientras se realizan pruebas aproximadas. Puede observar las combinaciones de interacción resultantes mediante AppVerifier. Aunque la detección aproximada no es exhaustiva, es fácil de implementar y automatizar, y puede detectar los errores más elusivos e imprevisibles.

Para obtener más información sobre las pruebas aproximadas, consulte la presentación Gamefest 2007 Pasos prácticos en Seguridad del juego.

Firma con Authenticode

Authenticode es un método para garantizar que los archivos ejecutables, los archivos DLL y los paquetes del instalador de Windows (archivos .msi) que recibe el usuario no se modifican de lo que un desarrollador publicó. Mediante el uso de una combinación de principios criptográficos, entidades de confianza y estándares del sector, Authenticode comprueba la integridad del contenido ejecutable. Microsoft proporciona una API criptográfica, CryptoAPI, que se puede usar para detectar automáticamente la manipulación del código firmado. Si se produce una fuga de seguridad después de una versión, se puede revocar un certificado y todo el código firmado con ese certificado dejará de autenticarse. Revocar un certificado revocará la validación de todos los títulos firmados con ese certificado. Windows se ha diseñado para trabajar con la firma de Authenticode y avisará a un usuario de código sin firmar, en situaciones específicas, que podrían exponer el equipo de un usuario para atacar.

Authenticode no debe considerarse un método para eliminar problemas de seguridad, sino un método para detectar alteraciones después de liberar un archivo ejecutable. Un archivo ejecutable o DLL que contiene un problema de seguridad que se puede aprovechar se puede firmar y comprobar mediante Authenticode, pero seguirá introduciendo el problema de seguridad en el nuevo sistema. Solo después de que se haya comprobado que un producto o una actualización sean seguros, el código debe estar firmado para asegurar a los usuarios que tienen una versión que no se ha alterado.

Incluso si un desarrollador considera que no hay ninguna amenaza de que se modifiquen sus versiones, otras tecnologías y servicios dependen de Authenticode. La firma de código es fácil de integrar y automatizar; no hay ninguna razón para que los desarrolladores no tengan sus versiones firmadas.

Para obtener más información sobre la firma con Authenticode, consulte Firma con Authenticode para desarrolladores de juegos.

Minimización de privilegios

En general, los procesos deben ejecutarse con el conjunto mínimo de privilegios necesarios para funcionar. En Windows Vista y Windows 7, esto se logra mediante el control de cuentas de usuario, lo que permite que el juego se ejecute como un usuario estándar en lugar de un administrador. Para Windows XP, normalmente los juegos siempre se ejecutan como administrador. Incluso en Windows Vista y Windows 7, a veces es necesario elevar a derechos de administrador completos para algunas operaciones específicas.

En los casos en los que el proceso se ejecuta con derechos administrativos completos, normalmente solo se requieren algunos derechos más allá de los de un usuario estándar. El acceso administrativo incluye muchos derechos que no son necesarios para el código legítimo, pero que un atacante podría usar, a través de alguna debilidad en el proceso. Algunos ejemplos de estos derechos incluyen SE_TAKE_OWNERSHIP, SE_DEBUG, SE_CREATE_TOKEN, SE_ASSIGNPRIMARYTOKEN, SE_TCB, SE_SECURITY, SE_LOAD_DRIVER, SE_SYSTEMTIME, SE_BACKUP, SE_RESTORE, SE_SHUTDOWN y SE_AUDIT (consulte Constantes de privilegios).

Aunque un proceso no puede obtener más derechos una vez iniciado, puede renunciar fácilmente a los derechos. En el inicio, el proceso puede usar inmediatamente las API de Win32 para quitar los derechos que no requiere.

Uso de características de Seguridad de Windows

Windows Vista y Windows 7 incluyen varias características nuevas que mejoran la seguridad del código. El Control de cuentas de usuario es ciertamente el más importante de comprender y adoptar, pero también hay otras características. Además de las tecnologías de Windows XP SP2, como firewall de Windows, prevención de ejecución de datos, comprobación de seguridad del búfer y controladores de excepciones seguros que también están disponibles en Windows Vista y Windows 7, hay tres características de seguridad más recientes que se deben tener en cuenta:

  • Característica de selección aleatoria de diseño de espacio de direcciones. Se habilita mediante la vinculación con la opción /DYNAMICBASE en Visual Studio 2005 Service Pack 1 o Visual Studio 2008. Esto hace que el sistema aleatorice las posiciones de muchos de los archivos DLL del sistema clave en el espacio de proceso, lo que hace que sea mucho más difícil escribir programas de ataque vulnerables que propagan ampliamente a través de Internet. Windows XP omite esta marca del enlazador y las versiones anteriores de Windows.
  • Los daños en el montón pueden provocar una clase completa de vulnerabilidades de seguridad, por lo que el sistema de memoria de Windows Vista y Windows 7 ahora admite un modo que finaliza el proceso si se detecta daños en el montón. Al llamar a HeapSetInformation con HeapEnableTermianteOnCorruption, se optará por este comportamiento. Esta llamada produce un error en Windows XP y en la versión anterior de Windows.
  • Al escribir servicios, se pueden configurar mediante una nueva característica para especificar qué privilegios son realmente necesarios, así como para limitar el acceso de recursos a un SID específico. Esto se realiza a través de ChangeSeviceConfig2, mediante SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO y SERVICE_CONFIG_SERVICE_SID_INFO.

Resumen

Desarrollar un juego para el marketplace actual y futuro es costoso y lento. Lanzar un juego con problemas de seguridad en última instancia costará más dinero y tiempo para corregir correctamente. Así pues, a todos los desarrolladores de juegos les interesa integrar herramientas y técnicas para mitigar los fallos de seguridad antes de su lanzamiento.

La información de este artículo es solo una introducción a lo que un estudio de desarrollo puede hacer para ayudarse a sí mismo y a sus clientes. Puede encontrar más información sobre las prácticas generales de seguridad y la información de seguridad en el Centro para desarrolladores de seguridad de Microsoft.