Partager via


Bonnes pratiques de sécurité dans le développement de jeux

Cet article discute des bonnes pratiques à utiliser dans le développement de jeux.

Introduction

Un nombre croissant de personnes jouent à des jeux en ligne et à des jeux avec du contenu créé par les utilisateurs. Cela, combiné à la sécurité croissante du système d’exploitation Microsoft Windows, signifie que les jeux deviennent une cible de plus en plus tentante pour les attaquants à exploiter. Les développeurs de jeux doivent accorder une grande importance à s’assurer que les jeux qu’ils publient ne créent pas de nouvelles failles de sécurité pour les attaquants à exploiter. Les développeurs de jeux ont la responsabilité et l’intérêt de contribuer à empêcher que les ordinateurs de leurs clients soient piratés par des données réseau malveillantes, des modifications d’utilisateurs ou des altérations. Si une vulnérabilité est exploitée, cela pourrait entraîner une perte de clients et/ou d’argent. Cet article décrit et explique certaines méthodes et outils courants pour augmenter la sécurité du code sans allonger de manière excessive le temps de développement.

Les trois erreurs les plus courantes commises par une équipe de développement lors de la sortie d’un produit sont :

  • Exiger des privilèges administratifs. Les jeux ne devraient pas nécessiter de privilèges administratifs. Pour plus de détails, veuillez consulter la section Contrôle de compte d’utilisateur pour les développeurs de jeux.
  • Ne pas utiliser de protection automatisée. Les développeurs n’utilisent généralement pas /GS, /SAFESEH ou /NX. Utiliser ces indicateurs de compilation/liens peut détecter ou éliminer de nombreuses failles de sécurité de base sans augmenter significativement la charge de travail. Ces indicateurs sont discutés plus loin dans cet article.
  • Utiliser des API interdites. Il existe de nombreuses API (strcpy, strncpy, etc.) sujettes aux erreurs de programmation et qui génèrent facilement des failles de sécurité. Les développeurs devraient remplacer ces API par des versions sécurisées. Visual Studio 2005 est livré avec un outil d’analyse de fichiers binaires qui peut automatiquement vérifier les fichiers objets pour les références aux API non sécurisées. Pour plus d’informations sur ce qu’il faut faire avec les informations générées par cet outil, veuillez consulter Repel Attacks on Your Code with the Visual Studio 2005 Safe C and C++ Libraries de Martyn Lovell. De plus, vous pouvez obtenir le fichier d’en-tête banned.h qui peut vous aider à supprimer les fonctions interdites du code (veuillez consulter les Outils de sécurité gratuits de Microsoft – banned.h).

Chacune des erreurs énumérées est non seulement courante mais facilement corrigeable sans changement significatif de la charge de travail de développement, des normes de codage ou de la fonctionnalité.

Exemples de code non sécurisé

Voici un exemple simple de ce qu’il faut pour permettre à un attaquant d’effectuer une attaque de dépassement de tampon :

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

    // ...
}

À première vue, ce code semble correct — il appelle une fonction sécurisée, après tout. Les données du réseau sont copiées dans un segment de 256 octets. La fonction strncpy repose sur la recherche d’un terminateur NULL dans la chaîne source ou est limitée par le nombre de tampons fourni. Le problème est que la taille du segment est incorrecte. Si les données du réseau ne sont pas validées ou si la taille du segment est incorrecte (comme dans cet exemple), un attaquant pourrait simplement fournir un grand segment pour écraser les données de la pile, après la fin du segment, avec toutes les données du paquet réseau. Cela permettrait à l’attaquant d’exécuter du code arbitraire en écrasant le pointeur d’instruction et en modifiant l’adresse de retour. La leçon la plus fondamentale de cet exemple est de ne jamais faire confiance aux entrées tant qu’elles n’ont pas été vérifiées.

Même si les données ne proviennent pas initialement du réseau, il y a toujours un risque potentiel. Le développement de jeux modernes nécessite de nombreuses personnes pour concevoir, développer et tester la même base de code. Il n’y a aucun moyen de savoir comment la fonction sera appelée à l’avenir. Demandez-vous toujours d’où proviennent les données et ce que pourrait contrôler un attaquant ? Bien que les attaques basées sur le réseau soient les plus courantes, elles ne sont pas les seules méthodes de création de failles de sécurité. Un attaquant pourrait-il créer un mod ou modifier un fichier enregistré d’une manière qui ouvre une faille de sécurité ? Qu’en est-il des fichiers image et son fournis par l’utilisateur ? Des versions malveillantes de ces fichiers pourraient être publiées sur Internet et créer des risques de sécurité dangereux pour vos clients.

En passant, utilisez strsafe.h ou Safe CRT au lieu de strncpy pour corriger l’exemple. Safe CRT est une refonte complète de la sécurité du runtime C et fait partie de Visual Studio 2005. Plus d’informations sur Safe CRT peuvent être trouvées dans Security Enhancements in the CRT de Michael Howard.

Moyens d’améliorer la sécurité

Il existe plusieurs façons d’améliorer la sécurité dans le cycle de développement. Voici quelques-unes des meilleures méthodes :

Lectures à propos de la sécurité

Le livre, Writing Secure Code, Second Edition de Michael Howard et David LeBlanc, fournit une explication approfondie et claire des stratégies et méthodes de prévention des attaques et d’atténuation des exploits. En commençant par des méthodes de conception de la sécurité dans une version jusqu’aux techniques pour sécuriser les applications réseau, le livre couvre tous les aspects dont un développeur de jeux a besoin pour aider à se protéger, protéger ses produits et ses clients contre les attaquants. Le livre peut être utilisé pour instaurer une culture de la sécurité dans un studio de développement. Ne pensez pas seulement à la sécurité du code comme un problème de développeur ou de testeur. Pensez la sécurité comme un élément que toute l’équipe, du chef de projet au designer en passant par le développeur et le testeur, doit prendre en compte lorsqu’elle travaille sur un projet. Plus il y a d’yeux qui participent au processus de révision, plus la chance de détecter une faille de sécurité avant la publication est grande.

Writing Secure Code, Second Edition peut être trouvé dans Microsoft Press Store et des informations de sécurité plus générales peuvent être trouvées dans Fending Off Future Attacks by Reducing Attack Surface de Michael Howard.

Michael Howard, David LeBlanc, et John Viega ont écrit un autre livre sur le sujet qui couvre tous les systèmes d’exploitation et langages de programmation courants intitulé, 19 Deadly Sins of Software Security.

Des présentations sur la sécurité axées sur des jeux peuvent être trouvées sur la page de téléchargement Microsoft XNA Developer Presentations.

Analyse de modélisation des menaces

Une analyse de modélisation des menaces est un bon moyen d’évaluer la sécurité d’un système, non pas dans un langage spécifique ou en utilisant un outil, mais d’une manière large, de bout en bout, qui peut être réalisée en quelques réunions. Lorsqu’un modèle de menace est correctement mis en œuvre, il peut identifier tous les points forts et faibles d’un système, sans ajouter une charge de travail ou un temps de réunion significatifs au projet. La méthode de modélisation des menaces met également l’accent sur l’idée d’évaluer la sécurité du système avant et pendant le processus de développement pour aider à garantir qu’une évaluation complète est effectuée tout en se concentrant sur les fonctionnalités les plus risquées. Cela peut être considéré comme un profil de sécurité. En n’étant pas basé sur un langage particulier ou en ne s’appuyant pas sur un outil spécifique, la modélisation des menaces peut être utilisée dans n’importe quel studio de développement travaillant sur n’importe quel projet dans n’importe quel genre. La modélisation des menaces est également une excellente méthode pour renforcer l’idée que la sécurité est la responsabilité de tous et non le problème de quelqu’un d’autre.

Lors de la modélisation des menaces, prêtez une attention particulière à :

  • Sources de données UDP
  • Les sources de données qui ne nécessitent pas d’authentification
  • Les sources de données qui sont fréquemment et normalement sondées dans le cadre d’une collecte d’informations à grande échelle
  • Toute capacité d’un client à envoyer directement des données à d’autres clients

Ce sont les domaines qui présentent un bon potentiel de faiblesses de sécurité.

Plus d’informations sur la modélisation des menaces peuvent être trouvées dans Threat Modeling et dans le livre Threat Modeling de Frank Swiderski et Window Snyder.

Prévention de l’exécution de données (/NX)

Un outil récent pour atténuer de multiples exploits est la prévention de l’exécution de données (DEP). Si vous incluez le commutateur /NX dans la commande de build, Visual Studio marquera les pages mémoire avec des indicateurs qui indiquent si le code a le droit de s’exécuter ou non. Tout programme tentant de s’exécuter dans une page mémoire non marquée avec l’autorisation EXECUTE provoquera une terminaison forcée du programme. La prévention est appliquée au niveau du processeur et affectera les développeurs qui utilisent du code auto-modifiant ou des compilateurs de langage JIT natif. Actuellement, seuls les processeurs Athlon64 et Opteron d’AMD et les processeurs Itanium et les derniers processeurs Pentium 4 d’Intel prennent en charge la prévention de l’exécution, mais il est prévu que tous les processeurs 32 bits et 64 bits prendront en charge la prévention de l’exécution à l’avenir. (Un schéma de protection contre la copie utilisé par un développeur peut être affecté par la prévention de l’exécution, mais Microsoft a travaillé avec les fournisseurs de protection contre la copie pour minimiser l’impact.) Il est une bonne pratique d’utiliser DEP.

Pour plus de détails sur DEP, veuillez consulter la section Prévention de l’exécution de données.

Vérification de la sécurité des tampons (/GS) et Image a des gestionnaires d’exceptions sûrs (/SAFESEH)

Vérification de la sécurité des tampons, spécifiée par l’indicateur du compilateur /GS, et Image a des gestionnaires d’exceptions sûrs, spécifiée par l’indicateur du lieur /SAFESEH (implémenté pour la première fois dans Visual Studio .NET 2003), peuvent faciliter la tâche des développeurs pour sécuriser le code.

L’utilisation de l’indicateur /GS incite le compilateur à construire une vérification pour certaines formes de dépassements de tampon basés sur la pile qui pourraient être exploités pour écraser l’adresse de retour d’une fonction. L’utilisation de /GS ne détectera pas tous les dépassements de tampon potentiels et ne devrait pas être considérée comme une solution universelle, mais comme une bonne technologie de défense en profondeur.

L’utilisation de l’indicateur /SAFESEH demandera au lieur de générer uniquement un exécutable ou une DLL s’il peut également générer une table des gestionnaires d’exceptions sûrs de l’exécutable ou de la DLL. La gestion d’exceptions structurées sécurisées (SafeSEH) élimine la gestion des exceptions comme cible d’attaques par dépassement de tampon en veillant à ce qu’avant qu’une exception ne soit distribuée, le gestionnaire d’exceptions soit enregistré dans la table des fonctions située dans le fichier image. Ces avantages de protection sont activés avec Windows XP SP2, Windows Server 2003, Windows Vista et Windows 7. De plus, pour que /SAFESEH fonctionne correctement, il doit être utilisé de manière tout ou rien. Toutes les bibliothèques contenant du code lié à un exécutable ou à une DLL doivent être compilées avec /SAFESEH ou la table ne sera pas générée.

Pour plus d’informations, veuillez consulter la section Vérification de la sécurité des tampons (/GS) et Image a des gestionnaires d’exceptions sûrs (/SAFESEH).

Voir également des informations sur l’indicateur /SDL de Microsoft Visual Studio 2012 et les améliorations de Visual Studio 2012 apportées à l’indicateur /GS.

PREfast

PREfast est un outil gratuit proposé par Microsoft qui analyse les chemins d’exécution dans le C ou C++ compilé pour aider à trouver des bugs d’exécution. PREfast fonctionne en parcourant tous les chemins d’exécution dans toutes les fonctions et en évaluant chaque chemin pour y déceler des problèmes. Initialement utilisé pour développer des pilotes et d’autres codes de noyau, cet outil peut aider les développeurs de jeux à gagner du temps en éliminant certains bugs difficiles à trouver ou ignorés par le compilateur. Utiliser PREfast est un excellent moyen de réduire la charge de travail et de concentrer les efforts à la fois de l’équipe de développement et de l’équipe de test. PREfast est disponible dans Visual Studio Team Suite et Visual Studio Team Edition for Software Developers en tant qu’analyse de code, activée par le commutateur du compilateur /analyze. (Cette option est également disponible dans la version gratuite du compilateur fournie avec le kit de développement logiciel Windows).

Remarque

Visual Studio 2012 prend en charge /analyze dans toutes les éditions. Pour plus d’informations sur la disponibilité de l’analyse de code dans toutes les éditions de Visual Studio, veuillez consulter la section Quoi de neuf dans l’analyse de code.

 

Grâce à l’utilisation d’annotations d’en-tête (en particulier pour les arguments de pointeur de tampon), PREfast peut révéler des problèmes supplémentaires, tels que les bugs de dépassement de mémoire, une source courante de plantages et de vulnérabilités potentielles de sécurité. Cela se fait en utilisant le langage d’annotation standard (SAL), qui est une forme de balisage pour les prototypes de fonction C/C++ qui fournit des informations supplémentaires sur la sémantique attendue des arguments pointeur et la corrélation avec les paramètres de longueur, les tailles de tampon déclarées, etc. Tous les en-têtes pour les systèmes d’exploitation Windows sont annotés, et ajouter du balisage SAL dans les en-têtes d’API publics de vos propres bibliothèques permet à PREfast d’effectuer des vérifications plus détaillées et agressives dans votre code client pour de telles API. Pour une introduction à SAL et des liens vers plus d’informations, consultez l’article de blog de Michael Howard intitulé « A Brief Introduction to the Standard Annotation Language (SAL) ».

Windows Application Verifier

Le vérificateur d’application Windows, ou AppVerifier, peut aider les testeurs en fournissant plusieurs fonctions dans un seul outil. L’AppVerifier est un outil qui a été développé pour rendre les erreurs de programmation courantes plus testables. AppVerifier peut vérifier les paramètres passés aux appels d’API, injecter des entrées erronées pour vérifier la capacité de gestion des erreurs, et consigner les modifications apportées au registre et au système de fichiers. AppVerifier peut également détecter les dépassements de tampon dans le tas, vérifier qu’une liste de contrôle d’accès (ACL) a été correctement définie et appliquer l’utilisation sûre des API de socket. Bien que non exhaustive, AppVerifier peut être un outil dans la boîte à outils du testeur pour aider un studio de développement à publier un produit de qualité.

Pour plus d’informations sur Application Verifier, veuillez consulter la section Application Verifier et Utilisation d’Application Verifier au sein de votre cycle de vie de développement logiciel.

Test à données aléatoires (fuzzing)

Tests de fuzzing est une méthode de test semi-automatisée qui peut améliorer les méthodologies de test actuelles. L’idée centrale derrière les tests de fuzzing est de faire une évaluation complète de toutes les entrées en entrant des données aléatoires pour voir ce qui casse ; cela inclut toutes les données réseau, les mods et les jeux enregistrés, etc. Les tests de fuzzing sont assez faciles à réaliser. Modifiez simplement des fichiers bien formés ou des données réseau en insérant des octets aléatoires, en inversant des octets adjacents ou en niant des valeurs numériques. 0xff, 0xffff, 0xffffffff, 0x00, 0x0000, 0x00000000 et 0x80000000 sont des valeurs qui sont efficaces pour exposer des failles de sécurité lors des tests de fuzzing. Vous pouvez observer les combinaisons d’interactions résultantes en utilisant AppVerifier. Bien que le fuzzing ne soit pas exhaustif, il est facile à mettre en œuvre et à automatiser, et il peut détecter les bugs les plus insaisissables et imprévisibles.

Pour plus d’informations sur les tests de fuzzing, voir la présentation Gamefest 2007 Practical Steps in Game Security.

Signature Authenticode

Authenticode est une méthode permettant de garantir que les fichiers exécutables, les fichiers DLL et les packages d’installation Windows (.msi files) que l’utilisateur reçoit ne sont pas modifiés par rapport à ce qu’un développeur a publié. En utilisant une combinaison de principes cryptographiques, d’entités de confiance et de normes de l’industrie, Authenticode vérifie l’intégrité du contenu exécutable. Microsoft fournit une API cryptographique, CryptoAPI, qui peut être utilisée pour détecter automatiquement les altérations du code signé. Si une fuite de sécurité survient après une publication, un certificat peut être révoqué et tout code signé avec ce certificat cessera de s’authentifier. La révocation d’un certificat annulera la validation de tous les titres signés avec ce certificat. Windows a été conçu pour fonctionner avec la signature Authenticode et alertera un utilisateur de code non signé, dans certaines situations, qui pourrait exposer le PC de l’utilisateur à une attaque.

Authenticode ne doit pas être considéré comme une méthode permettant d’éliminer les problèmes de sécurité, mais comme une méthode permettant de détecter les altérations après qu’un exécutable a été publié. Un exécutable ou une DLL contenant un problème de sécurité exploitable peut être signé et vérifié à l’aide d’Authenticode, mais il introduira tout de même le problème de sécurité dans le nouveau système. Ce n’est qu’après qu’un produit ou une mise à jour a été vérifié comme étant sûr que le code doit être signé pour assurer aux utilisateurs qu’ils ont une version qui n’a pas été altérée.

Même si un développeur estime qu’il n’y a pas de risque que ses versions soient modifiées, d’autres technologies et services dépendent d’Authenticode. La signature de code est facile à intégrer et à automatiser ; il n’y a aucune raison pour que les développeurs ne fassent pas signer leurs versions.

Pour plus d’informations sur la signature Authenticode, veuillez consulter la section Signature Authenticode pour les développeurs de jeux.

Réduire les privilèges

En général, les processus doivent s’exécuter avec le minimum de privilèges requis pour fonctionner. Sous Windows Vista et Windows 7, cela se fait en utilisant le contrôle de compte utilisateur (UAC), permettant au jeu de s’exécuter en tant qu’utilisateur standard plutôt qu’en tant qu’administrateur. Pour Windows XP, les jeux s’exécutent généralement toujours en tant qu’administrateur. Même sous Windows Vista et Windows 7, il est parfois nécessaire de s’élever aux droits d’administrateur complets pour certaines opérations spécifiques.

Dans les cas où le processus s’exécute avec des droits administratifs complets, généralement seuls quelques droits au-delà de ceux d’un utilisateur standard sont réellement requis. L’accès administratif inclut de nombreux droits qui ne sont pas requis par un code légitime, mais qui pourraient être utilisés par un attaquant, par le biais d’une faille dans le processus. Des exemples de tels droits incluent 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, et SE_AUDIT (voir Priviledge Constants).

Bien qu’un processus ne puisse pas obtenir plus de droits une fois démarré, il peut facilement abandonner des droits. Au démarrage, le processus peut immédiatement utiliser les API Win32 pour supprimer les droits dont il n’a pas besoin.

Utiliser les fonctionnalités de sécurité de Windows

Windows Vista et Windows 7 incluent un certain nombre de nouvelles fonctionnalités qui améliorent la sécurité du code. Le contrôle de compte utilisateur (UAC) est certainement le plus important à comprendre et à adopter, mais il existe d’autres fonctionnalités également. En plus des technologies de Windows XP SP2, telles que le pare-feu Windows, la prévention de l’exécution de données, la vérification de la sécurité des tampons et les gestionnaires d’exceptions sûrs, qui sont également disponibles sur Windows Vista et Windows 7, il existe trois nouvelles fonctionnalités de sécurité à considérer :

  • La fonctionnalité de randomisation de la disposition de l’espace d’adressage en opt-in. Ceci est activé en liant avec l’option /DYNAMICBASE sur Visual Studio 2005 Service Pack 1 ou Visual Studio 2008. Cela amène le système à randomiser les positions de nombreux des DLL système clés dans votre espace de processus, rendant beaucoup plus difficile l’écriture de programmes d’attaque exploitables qui se propagent largement sur Internet. Cet indicateur de lien est ignoré par Windows XP et les versions antérieures de Windows.
  • La corruption du tas peut conduire à toute une classe d’exploits de sécurité, donc le système de mémoire de Windows Vista et Windows 7 prend désormais en charge un mode qui termine le processus si une corruption du tas est détectée. Appeler HeapSetInformation avec HeapEnableTermianteOnCorruption activera ce comportement. Cet appel échoue sur Windows XP et les versions antérieures de Windows.
  • Lors de l’écriture de services, ils peuvent être configurés à l’aide d’une nouvelle fonctionnalité pour spécifier quels privilèges sont réellement requis, ainsi que pour limiter l’accès aux ressources à un SID spécifique. Cela se fait via ChangeSeviceConfig2, en utilisant SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO et SERVICE_CONFIG_SERVICE_SID_INFO.

Résumé

Développer un jeu pour le marché actuel et futur est coûteux et prend du temps. Publier un jeu avec des problèmes de sécurité coûtera finalement plus d’argent et de temps pour le corriger correctement. Il est donc dans l’intérêt de tous les développeurs de jeux d’intégrer des outils et des techniques pour atténuer les exploits de sécurité avant la publication.

Les informations contenues dans cet article ne sont qu’une introduction à ce qu’un studio de développement peut faire pour s’aider lui-même et ses clients. Vous trouverez plus d’informations sur les pratiques de sécurité générales et les informations de sécurité dans le Centre de développement Microsoft Security.