Liste de contrôle minimale de sécurité pour le développement d'applications Windows

· Mis à jour le: · · Développement Windows, Sécurité, Conception, C# / .NET, Win32

Télécharger la version Excel de la liste de contrôle

Quand on parle de sécurité des applications Windows, le sujet a tendance à s’élargir rapidement. Zero trust, EDR, SBOM, gestion des certificats, gestion des vulnérabilités. Tout cela est important, mais en pratique, il existe d’abord plusieurs bases qu’on ne veut pas manquer.

C’est particulièrement vrai pour des applications comme celles-ci, où combler les lacunes de base est plus efficace que des « défenses avancées » :

  • applications de bureau WPF / WinForms / WinUI
  • applications Win32 en C++ / C#
  • intégration d’équipements, intégration de fichiers, connexions à des bases de données, outils de distribution interne
  • applications métier disposant d’un mécanisme de mise à jour automatique
  • configurations incluant des services Windows ou des EXE auxiliaires

Dans le développement d’applications Windows, il est plus réaliste de commencer par ne laisser aucune faille manifestement dangereuse, plutôt que de vouloir tout perfectionner d’un coup. Ici, nous organisons, dans l’ordre conception, implémentation, distribution et exploitation, les points minimaux à ne pas manquer, sous une forme facile à vérifier.

1. La conclusion, d’abord

  • Ce qu’on ne veut pas manquer en premier lieu, c’est de ne pas demander de privilèges administrateur inutiles, de signer le code, de ne pas conserver d’informations confidentielles en clair, et de ne jamais désactiver la vérification des certificats.
  • Pour une application Windows, les artefacts de distribution eux-mêmes constituent la surface d’attaque. Il est plus sûr de tout examiner, jusqu’aux EXE / DLL / MSI / MSIX / modules de mise à jour automatique.
  • ServerCertificateValidationCallback => true, les chaînes de connexion en clair, le chargement négligent de type LoadLibrary("foo.dll"), et l’exécution de SQL par concaténation de chaînes sont des points à éviter, même au niveau minimal.
  • Si seule une partie du traitement nécessite des privilèges administrateur, il est plus sûr de séparer uniquement cette partie dans un EXE ou un service distinct, plutôt que d’élever toute l’application.
  • Une application distribuée sous Windows devrait partir du principe signature + horodatage. Au-delà de la confiance des utilisateurs, cela facilite aussi la détection des altérations et les explications opérationnelles.
  • Pour les informations confidentielles stockées, on choisit entre DPAPI / ProtectedData et le Credential Locker selon l’usage. Il faut au moins sortir de la situation où elles sont placées en clair dans appsettings.json.
  • Multiplier les journaux n’est pas forcément une bonne chose. Laisser tels quels des tokens, mots de passe, chaînes de connexion, informations personnelles ou corps complets de requêtes fait du journal lui-même l’acteur principal de l’incident.

La sécurité minimale consiste moins à ajouter des fonctionnalités spéciales qu’à ne pas laisser subsister de comportements par défaut dangereux ni d’implémentations bâclées.

2. Le périmètre de cet article et ce que signifie « le minimum »

2.1. Le périmètre couvert

Les applications Windows envisagées dans cet article sont les suivantes.

  • applications de bureau WPF / WinForms / WinUI
  • applications Win32 en C++ / C#
  • outils de distribution interne, outils d’intégration d’équipements, outils de surveillance
  • configurations incluant des EXE auxiliaires, des services Windows, des updaters
  • logiciels métier distribués en EXE / MSI / MSIX

Le « minimum » dont il est question ici ne désigne pas une forme finale qui passerait un audit, mais les points dont l’absence entraîne normalement un incident.

2.2. Ce qui n’est pas couvert

En revanche, certains sujets sont exclus du cœur de cet article.

  • la conception zero trust à l’échelle de l’entreprise
  • l’exploitation globale d’EDR / SIEM / DLP / MDM
  • le durcissement détaillé des pilotes en mode noyau
  • la conception de schémas cryptographiques à partir de zéro
  • l’analyse de menaces avancée ou les procédures de criminalistique numérique

Autrement dit, nous ne traitons pas de « vastes mesures de sécurité à l’échelle de l’organisation », mais de la ligne de base qu’un développeur d’applications Windows peut et doit sécuriser par lui-même avant la publication.

3. La liste de contrôle à consulter en premier

Avant d’entrer dans les détails, voici d’abord un tableau qui donne une vue d’ensemble. Cela seul suffit déjà à repérer les points à revoir.

3.1. Vue d’ensemble

Point à vérifier Action minimale Anti-pattern typique
Privilèges d’exécution Baser sur asInvoker, en isolant uniquement les traitements nécessitant une élévation Mettre toute l’application en requireAdministrator
Fiabilité des artefacts de distribution Signer le code des EXE / DLL / MSI / MSIX, avec horodatage Distribuer sans signature
Mise à jour Fixer la source de mise à jour, détecter les altérations via HTTPS et vérification de signature Écraser directement après un téléchargement en HTTP
Informations confidentielles Ne pas placer de secrets dans le code source ou une configuration en clair ; utiliser DPAPI / Credential Locker, etc. Placer des clés API ou des chaînes de connexion en clair dans un fichier de configuration
Communication Utiliser HTTPS et ne jamais désactiver la vérification des certificats Contourner en permanence la vérification des certificats avec return true
Entrées externes Valider systématiquement SQL, fichiers, IPC, URI, CSV, JSON, etc. Laisser tout passer sous prétexte que « c’est un outil interne »
Chargement des DLL Utiliser des chemins absolus, SetDefaultDllDirectories, et un ordre de recherche sûr Laisser LoadLibrary("foo.dll") dépendre du répertoire courant
Journalisation Masquer tokens, mots de passe et PII ; distinguer les erreurs destinées aux utilisateurs Afficher ou enregistrer tels quels les détails d’exception et les chaînes de connexion
Dépendances Mettre à jour en continu le SDK, NuGet, les runtimes VC++, les dépendances open source Les figer pendant des années sans suivre les informations de vulnérabilité

3.2. Baser les privilèges sur asInvoker

C’est le premier point à revoir dans une application Windows. Faire tourner toute l’application avec des privilèges administrateur signifie que les bugs, les substitutions de DLL, les erreurs de lecture des fichiers de configuration et les défauts de validation des entrées externes s’exécutent directement avec ces privilèges élevés.

La politique de base est la suivante.

  • les applications d’interface ordinaires tournent en asInvoker
  • seuls les traitements nécessitant des privilèges administrateur sont isolés dans un processus ou un service séparé
  • l’élévation n’a lieu qu’au moment précis où elle est nécessaire
  • les entrées transmises aux EXE auxiliaires ou aux services sont elles aussi validées

Si votre application de bureau ne fait normalement que consulter et modifier des données, et que seules l’installation ou la modification des paramètres du pare-feu nécessitent des privilèges administrateur, il est plus sûr de confier uniquement les parties nécessitant une élévation à un broker, plutôt que de mettre toute l’application en requireAdministrator.

<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
  <security>
    <requestedPrivileges>
      <requestedExecutionLevel level="asInvoker" uiAccess="false" />
    </requestedPrivileges>
  </security>
</trustInfo>

« C’est plus simple si ça tourne en administrateur » finit presque toujours par se payer plus tard. Faire tourner l’application avec le minimum de privilèges, et n’isoler que les opérations réellement nécessaires, réduit considérablement le rayon d’impact d’un incident.

3.3. Signer les binaires et les installateurs

Sous Windows, la fiabilité des artefacts de distribution compte énormément. Ce que les utilisateurs manipulent, ce n’est pas le code source, mais l’EXE, la DLL, le MSI, le MSIX, l’updater. Si ces éléments ne sont pas signés, les explications opérationnelles, la détection des altérations et la confiance au moment de la distribution en pâtissent tous.

Voici, au minimum, ce qu’il faut regarder.

  • signer les EXE / DLL / MSI / MSIX
  • signer non seulement l’installateur, mais aussi les binaires auxiliaires utilisés pour la mise à jour
  • ajouter un horodatage
  • inclure l’expiration du certificat et la procédure de renouvellement dans la procédure de publication

Une signature sans horodatage pose particulièrement problème lors de la vérification après l’expiration du certificat. Plutôt que de considérer que « c’est signé, donc c’est terminé », il est plus stable d’intégrer la signature et l’horodatage dans la procédure de publication.

Si vous utilisez MSIX, la signature du paquet est un prérequis. Même en distribution MSI / EXE, il vaut mieux signer au moins l’installateur lui-même et les principaux binaires exécutables.

3.4. Fixer le canal de mise à jour et intégrer la détection des altérations

Pour une application Windows moderne, le canal de mise à jour est utilisé bien plus longtemps que l’installation initiale. Si ce point est négligé, même une application soigneusement conçue verra son updater devenir le maillon le plus faible.

Voici les cinq points minimaux à considérer autour des mises à jour.

  • récupérer les fichiers de mise à jour en partant du principe HTTPS
  • vérifier la signature ou le hachage de l’artefact de mise à jour téléchargé
  • empêcher que l’URL source de mise à jour puisse être remplacée sans restriction via le code ou la configuration
  • signer également le module de mise à jour lui-même
  • définir une procédure de retour en arrière ou de récupération en cas d’échec

Si vous pouvez adopter MSIX + App Installer, il est plus facile de rapprocher le mécanisme de mise à jour de l’OS lui-même. En revanche, si vous utilisez votre propre updater, vous devez vérifier à la fois la sécurité des communications et l’authenticité des artefacts distribués. HTTPS seul protège le « canal de communication », mais ne garantit pas que « ce fichier est bien celui que vous avez publié ».

3.5. Ne pas placer d’informations confidentielles dans le code source ou une configuration en clair

C’est un point où les incidents surviennent vraiment souvent en pratique. Avec des raisonnements du type « c’est un outil interne » ou « de toute façon, on ne distribue qu’un exe », on a tendance à placer chaînes de connexion, clés API, identifiants de dossiers partagés et tokens fixes dans le code source ou les fichiers de configuration.

Voici, au minimum, les pratiques de stockage à éviter.

  • des clés API écrites en dur dans le code source
  • des mots de passe en clair dans appsettings.json ou app.config
  • des chaînes de connexion versionnées dans le dépôt
  • une conception qui place la clé de déchiffrement et le texte chiffré au même endroit
  • des identifiants fixes communs à tous les utilisateurs plutôt que propres à chacun

Les options réalistes pour une application Windows se résument globalement à ces quatre-là.

  • Vous voulez stocker des identifiants Windows Pour une packaged desktop app / une application WinUI, envisagez le Credential Locker
  • Vous voulez chiffrer des secrets stockés localement Pour Win32 / .NET, utilisez DPAPI / ProtectedData
  • La cible prend en charge l’authentification Windows ou intégrée Si possible, ne faites pas porter de mot de passe à l’application
  • Les secrets peuvent être gérés côté cloud ou serveur Privilégiez une conception qui n’intègre pas de secrets à longue durée de vie dans le client

En C#, même se contenter d’utiliser DPAPI comme ceci est déjà nettement préférable à un stockage en clair.

using System.Security.Cryptography;
using System.Text;

byte[] plaintext = Encoding.UTF8.GetBytes(secretText);
byte[] ciphertext = ProtectedData.Protect(
    plaintext,
    optionalEntropy: null,
    scope: DataProtectionScope.CurrentUser);

Ce qui compte ici, ce n’est pas « c’est chiffré, donc c’est sûr », mais de décider dans la conception qui peut déchiffrer. Le choix entre CurrentUser et LocalMachine change considérablement la signification.

Pour une connexion SQL Server, dans un environnement on-premises, l’authentification Windows peut souvent être le premier choix. Si vous devez absolument inclure des identifiants dans la chaîne de connexion, il est plus sûr de conserver au moins Persist Security Info=False et de ne pas les laisser dans un fichier de configuration en clair.

3.6. Partir du principe HTTPS pour les communications, sans jamais désactiver la vérification des certificats

Un contournement ajouté « juste pour le développement » finit par rester tel quel en production. La plupart des incidents liés aux communications suivent ce schéma.

Voici le type de code ou de configuration qui a tendance à rester dans les livrables.

  • ServicePointManager.ServerCertificateValidationCallback += ... => true
  • HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
  • livrer avec la vérification de révocation des certificats désactivée
  • laisser en production du code supposant un certificat auto-signé de développement

La politique minimale est simple.

  • les communications en production utilisent HTTPS
  • ne jamais contourner en permanence la vérification des certificats
  • si un assouplissement exceptionnel de la vérification est nécessaire, le limiter à des hôtes et des certificats spécifiques
  • éliminer de façon fiable le code de contournement de développement via des conditions de build ou de configuration
  • en .NET, tenir compte également de la vérification de révocation

Voici, en général, à quoi ressemble le mauvais exemple.

ServicePointManager.ServerCertificateValidationCallback +=
    (_, _, _, _) => true;

Cela semble pratique à première vue, mais cela revient à peu près à « laisser passer cette communication HTTPS quel que soit l’interlocuteur ». Retirer la vérification des certificats, c’est vider HTTPS d’une bonne partie de sa substance, même si le protocole est bien utilisé.

3.7. Traiter toutes les entrées externes comme des « entrées non fiables »

Une application Windows n’est pas une application web, ce qui rend facilement la validation des entrées trop laxiste. Mais en réalité, les points d’entrée pour les données externes sont plus nombreux qu’on ne le pense.

  • chemins de fichiers
  • CSV / Excel / JSON / XML
  • arguments de ligne de commande
  • named pipe / socket / COM / RPC / gRPC
  • chaînes transmises à la base de données
  • valeurs de registre
  • presse-papiers
  • URL / deep link
  • données renvoyées par des équipements externes ou des SDK

Voici en particulier les trois points que l’on ne veut absolument pas manquer.

  1. Toujours paramétrer le SQL Ne jamais construire de SQL par concaténation de chaînes.
  2. Normaliser les chemins de fichiers avant de les utiliser Ne jamais utiliser directement un chemin fourni par l’utilisateur pour supprimer, écraser ou extraire.
  3. Appliquer une limite de taille et une vérification du format lors de la lecture de fichiers externes « Le fichier s’est ouvert, donc c’est sûr » n’est pas un raisonnement valable.

Pour prendre l’exemple du SQL, voici ce qu’on veut éviter.

var sql = "SELECT * FROM Users WHERE Name = '" + userName + "'";

Au minimum, on veut se rapprocher de ceci.

using System.Data;
using Microsoft.Data.SqlClient;

using var cmd = connection.CreateCommand();
cmd.CommandText = "SELECT * FROM Users WHERE Name = @name";
cmd.Parameters.Add("@name", SqlDbType.NVarChar, 256).Value = userName;

« C’est un outil interne, donc les entrées sont fiables » est une hypothèse assez dangereuse. En réalité, des CSV corrompus, des noms de fichiers inattendus, des données obsolètes en base, des erreurs de saisie de l’exploitant, ou du JSON à moitié valide écrit par un autre outil arrivent normalement.

3.8. Ne jamais laisser l’origine du chargement des DLL ambiguë

C’est un piège typiquement lié à Windows. Charger une DLL uniquement par son nom, comme avec LoadLibrary("foo.dll"), peut, selon l’ordre de recherche, faire récupérer une DLL provenant d’un emplacement non voulu.

Ce qu’il faut faire est bien établi.

  • indiquer si possible le chemin absolu de la DLL
  • configurer SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS) tôt dans l’initialisation
  • ajouter explicitement des emplacements de recherche avec AddDllDirectory
  • éviter les conceptions qui transmettent directement le résultat de SearchPath à LoadLibrary
  • ne pas s’appuyer exclusivement sur le safe DLL search mode

Pour du code natif, par exemple, il est judicieux d’intégrer ceci tôt dans l’initialisation du processus.

SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);

Puis, on enregistre uniquement les répertoires supplémentaires nécessaires avec AddDllDirectory.

Ce point est facilement négligé parce que « ça marche normalement », mais si le répertoire de travail change chez le client ou qu’une DLL d’un autre produit se trouve dans le PATH, l’application se casse silencieusement. Au-delà de la sécurité, cela contribue aussi grandement à la prévention des incidents.

3.9. Ne pas exposer d’informations confidentielles dans les journaux et les exceptions

Multiplier les journaux pour faciliter les investigations en cas d’incident est important. Mais les journaux deviennent aussi facilement le cimetière des informations confidentielles.

Voici, au minimum, ce qu’il faut revoir concernant la journalisation.

  • ne pas journaliser les mots de passe, Bearer tokens, clés API
  • ne pas journaliser une chaîne de connexion dans son intégralité
  • masquer les informations personnelles et le contenu des données métier
  • séparer les détails d’exception entre l’écran destiné à l’utilisateur et le journal interne
  • ne pas activer en production la journalisation des PII destinée au débogage
  • revoir les permissions des emplacements de stockage des dumps et des traces

Les versions récentes de .NET facilitent également une organisation fondée sur la rédaction (redaction). Il faut au moins abandonner l’approche « on transforme tout en chaîne de caractères et on le journalise tel quel ».

Voici quelques échecs fréquents.

  • enregistrer intégralement le corps des requêtes/réponses HTTP
  • afficher le token ou l’ensemble des en-têtes en cas d’échec d’authentification
  • afficher directement le message d’exception dans une MessageBox
  • inclure tous les journaux confidentiels dans le ZIP de maintenance

L’affichage des erreurs se sépare, par exemple, comme ceci.

  • Pour l’utilisateur : « La connexion au serveur a échoué. Veuillez vérifier vos paramètres réseau et l’URL. »
  • Journal interne : hôte cible de l’échec, type d’erreur TLS, ID de corrélation, stack trace, nombre de tentatives

Cette seule séparation améliore considérablement l’équilibre entre la prévention des fuites d’information et la capacité d’investigation.

3.10. Ne pas négliger les bibliothèques dépendantes et les outils de développement

Le dernier point est discret, mais à fort impact. Même en construisant soigneusement le corps de l’application, conserver un runtime obsolète ou des bibliothèques dépendantes présentant des vulnérabilités connues sape les fondations.

Les points à surveiller ne sont pas si nombreux.

  • maintenir le SDK / runtime .NET dans une version encore supportée
  • vérifier régulièrement les mises à jour des dépendances NuGet / open source
  • pour le C++, gérer les versions des redistribuables du runtime et des DLL externes
  • inclure la vérification des informations de vulnérabilité dans la checklist avant publication
  • prévoir des smoke tests pour éviter que les mises à jour de dépendances ne cassent silencieusement l’application

Ici, « on le fera plus tard, en une fois » est l’attitude la plus dangereuse. Laisser la situation six mois, un an, et l’écart de mise à jour devient si important que la remédiation de sécurité elle-même se transforme en travail lourd.

4. Liste de contrôle avant publication

Voici une forme directement utilisable comme modèle pour les revues et les décisions de mise en production. Pour faciliter la vérification sous forme de tableau, les points minimaux à examiner avant publication sont classés par catégorie.

4.1. Privilèges et mode d’exécution

Point de contrôle Vérifié Remarques
Le démarrage normal s’effectue en asInvoker  
Les traitements nécessitant des privilèges administrateur sont isolés dans un EXE / service distinct, etc.  
En cas d’utilisation d’un service, le compte d’exécution n’est pas plus privilégié que nécessaire  
Les responsabilités sous %ProgramFiles% et sous les données utilisateur sont séparées  

4.2. Distribution et signature

Point de contrôle Vérifié Remarques
Les EXE / DLL / MSI / MSIX / updater sont signés  
Les signatures comportent un horodatage  
L’expiration du certificat et la procédure de renouvellement sont incluses dans le flux de publication  
La méthode de vérification de hachage / détection d’altération des artefacts est définie  

4.3. Mise à jour

Point de contrôle Vérifié Remarques
La récupération des mises à jour s’effectue en HTTPS  
La signature ou le hachage est vérifié après le téléchargement  
La conception rend difficile le remplacement arbitraire de l’URL source de mise à jour  
Une politique de retour en arrière ou de nouvelle tentative existe en cas d’échec de la mise à jour  

4.4. Informations confidentielles

Point de contrôle Vérifié Remarques
Les mots de passe, clés API et chaînes de connexion ne sont pas écrits en dur dans le code source  
Aucun secret n’est placé dans un fichier de configuration en clair  
Les secrets devant être stockés localement sont protégés par DPAPI / Credential Locker, etc.  
Là où c’est possible, on se rapproche de l’authentification Windows ou des identifiants utilisateur  

4.5. Communication

Point de contrôle Vérifié Remarques
Les communications en production utilisent HTTPS  
DangerousAcceptAnyServerCertificateValidator ou => true n’est pas resté dans les livrables  
La vérification de révocation et la validation du nom d’hôte sont prises en compte  
Aucun code ou paramétrage supposant un certificat de développement ne s’est glissé en production  

4.6. Entrées et accès aux données

Point de contrôle Vérifié Remarques
Le SQL est paramétré  
Les entrées en ligne de commande, fichiers, IPC, URI, etc. ont des limites et des vérifications de format  
Les opérations sur les chemins sont normalisées pour empêcher toute sortie de la racine  
Les messages d’exception ne sont pas affichés tels quels à l’écran  

4.7. DLL et environnement d’exécution

Point de contrôle Vérifié Remarques
L’origine du chargement des DLL est explicite  
L’ordre de recherche est contrôlé via SetDefaultDllDirectories / AddDllDirectory, etc.  
Le chargement des DLL n’est pas laissé au répertoire courant ou au PATH  
L’ensemble des fichiers nécessaires au chargement dynamique chez le client est identifié  

4.8. Journalisation et exploitation

Point de contrôle Vérifié Remarques
Aucun token, mot de passe ou PII n’est journalisé  
Le journal interne et les messages destinés aux utilisateurs sont séparés  
Les permissions des emplacements de stockage des dumps / traces / journaux ont été revues  
L’état de mise à jour du SDK et des bibliothèques dépendantes est vérifié  

5. Idées reçues courantes

Voici, en pratique, les idées reçues que l’on rencontre le plus souvent.

5.1. « C’est un outil interne, donc ça va »

Même un outil interne connaît normalement des fichiers corrompus, des erreurs de manipulation, des appareils personnels, des dossiers partagés, des DLL obsolètes et des configurations de privilèges négligées. Ne pas être exposé sur Internet n’élimine pas la surface d’attaque.

5.2. « C’est HTTPS, donc c’est sûr »

HTTPS est important, mais désactiver la vérification des certificats en réduit fortement la portée. De plus, pour la distribution des mises à jour, HTTPS seul ne suffit pas : la vérification de l’authenticité des artefacts est également nécessaire.

5.3. « C’est chiffré, donc c’est sûr »

Sans clarifier l’emplacement de la clé de déchiffrement, les droits de déchiffrement, ainsi que les limites entre utilisateurs et entre machines, le chiffrement seul ne suffit pas. En particulier, utiliser une valeur protégée avec LocalMachine en pensant qu’il s’agit d’un « secret propre à chaque utilisateur » mène plus tard à de la confusion.

5.4. « Plus de journaux, plus facile à investiguer »

Si les journaux sont volumineux mais laissent fuir tokens et informations personnelles, cela devient un incident en soi. Si l’on veut de la capacité d’investigation, il faut d’abord décider ce que l’on conserve et ce que l’on masque.

5.5. « Il suffit de faire tourner en administrateur pour que le problème disparaisse »

C’est plus simple au début, mais cela finit généralement par poser des difficultés au niveau de l’UAC, de la distribution, du support, des limites de privilèges, du chargement des DLL et des emplacements de stockage des fichiers. Le moindre privilège est plus stable sur le long terme.

6. Un ordre de priorité approximatif

Si tout faire d’un coup est trop lourd, voici approximativement l’ordre de priorité.

  1. Revoir les privilèges administrateur Commencer par abandonner l’usage systématique de requireAdministrator.
  2. Signature et horodatage Mettre en ordre la fiabilité des artefacts de distribution.
  3. Mettre les secrets à l’abri Sortir les secrets du code source et de la configuration en clair.
  4. Corriger HTTPS + la vérification des certificats Supprimer la famille => true des livrables.
  5. Revoir les entrées SQL / fichiers / IPC Réduire la concaténation de chaînes et les entrées non validées.
  6. Fixer le chargement des DLL Abandonner le chargement par nom seul et la dépendance au PATH.
  7. Masquer les journaux S’assurer que les journaux ne deviennent pas un sinistre secondaire en cas d’incident.
  8. Régulariser les mises à jour de dépendances Intégrer une vérification à chaque publication.

Dans cet ordre, il est plus facile d’avancer dans l’esprit de « combler d’abord les failles manifestement dangereuses ».

7. Résumé

Avant d’introduire des produits spéciaux ou des dispositifs massifs, la sécurité du développement d’applications Windows change déjà considérablement en mettant simplement en ordre ces sept points : privilèges, signature, informations confidentielles, communication, entrées, DLL et journalisation.

En résumant la ligne minimale en une phrase par point, cela donne ceci.

  • ne pas faire tourner toute l’application avec des privilèges administrateur
  • signer les artefacts de distribution et les mises à jour, avec horodatage
  • ne pas placer d’informations confidentielles dans le code source ou une configuration en clair
  • utiliser HTTPS sans jamais désactiver la vérification des certificats
  • ne pas faire confiance aux entrées externes que sont SQL, fichiers, IPC, etc.
  • ne jamais laisser l’origine du chargement des DLL ambiguë
  • ne pas exposer d’informations confidentielles dans les journaux
  • ne pas négliger les bibliothèques dépendantes

Le sujet de la sécurité est vaste, mais il n’est pas nécessaire de tout faire dès le départ. Il vaut cependant la peine de mettre en place, très tôt, ce minimum absolu : ne jamais livrer de comportements par défaut dangereux tels quels.

8. Références

Articles récents partageant les mêmes étiquettes, pour approfondir des sujets proches.

Ces pages replacent le sujet dans un contexte plus large de services et de décisions.

Cet article est directement lié aux services suivants.

Développement d'applications Windows

Comme il s'agit de revoir l'ensemble d'une application Windows - conception des privilèges, méthode de distribution, méthode de mise à jour, jusqu'à la conception des journaux -, ce sujet s'accorde naturellement avec notre service de développement d'applications Windows.

Questions fréquentes

Questions souvent posées lors d’une consultation sur le sujet de cet article.

Que faut-il vérifier en premier pour la sécurité d'une application Windows ?
Quatre points : ne pas demander de privilèges administrateur inutiles, signer le code, ne pas conserver d'informations confidentielles en clair, et ne jamais désactiver la vérification des certificats. La sécurité minimale consiste moins à ajouter des fonctionnalités spéciales qu'à ne pas laisser subsister des comportements par défaut dangereux ou des implémentations bâclées. Le contournement permanent de la vérification des certificats, les chaînes de connexion en clair, le chargement de DLL laissé au hasard du répertoire courant, et l'exécution de SQL par concaténation de chaînes sont des points à éviter, même au niveau minimal.
Ne faut-il jamais faire tourner toute l'application avec des privilèges administrateur ?
Il vaut mieux l'éviter. Faire tourner toute l'application avec des privilèges administrateur signifie que les bugs, les substitutions de DLL, les erreurs de lecture des fichiers de configuration et les défauts de validation des entrées externes s'exécutent directement avec ces privilèges élevés. La politique de base consiste à faire tourner les applications d'interface ordinaires en asInvoker, à isoler dans un processus ou un service séparé uniquement les traitements nécessitant des privilèges administrateur, et à n'élever les privilèges qu'au moment précis où c'est nécessaire.
Où faut-il stocker les clés API et les chaînes de connexion ?
Il faut d'abord sortir de la situation où elles sont placées en clair dans le code source ou dans des fichiers de configuration comme appsettings.json. Pour les informations confidentielles stockées localement, on choisit entre DPAPI / ProtectedData et le Credential Locker selon l'usage. Par ailleurs, si l'on laisse des tokens, mots de passe, chaînes de connexion ou informations personnelles tels quels dans les journaux, le journal lui-même devient l'acteur principal de l'incident ; un masquage est donc nécessaire.
La signature de code est-elle nécessaire même pour une application distribuée en interne ?
Il vaut mieux la considérer comme un prérequis. Pour une application Windows, les artefacts de distribution eux-mêmes (EXE / DLL / MSI / MSIX / module de mise à jour automatique) constituent la surface d'attaque. La signature de code accompagnée d'un horodatage permet la détection des altérations, renforce la confiance des utilisateurs et facilite les explications sur le plan opérationnel. Le mécanisme de mise à jour doit lui aussi fixer sa source et permettre la détection des altérations grâce à HTTPS et à la vérification de la signature.

Profil de l’auteur

Page de présentation de l’auteur de l’article.

Go Komura

Représentant de KomuraSoft LLC

Spécialisé dans le développement de logiciels Windows, le conseil technique et l’analyse de pannes, notamment pour les systèmes existants et les incidents difficiles à reproduire.

Retour au blog