Stocker les secrets des applications Windows - Éviter les configurations en clair avec DPAPI

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

Dans l’article précédent, « Liste de contrôle minimale pour la sécurité du développement d’applications Windows », nous avions posé la ligne de base : « ne pas placer de secrets dans le code source ou dans une configuration en clair » et « sous Win32 / .NET, utiliser DPAPI / ProtectedData ».

Cette fois, nous approfondissons un peu plus l’un de ces points : « utiliser DPAPI pour être, au minimum, meilleur que le texte en clair ».

Cet article s’adresse aux applications Windows du type suivant :

  • Applications de bureau WPF / WinForms / WinUI
  • Clients Windows en C# / .NET
  • Applications tentées de stocker des identifiants de connexion ou des jetons API dans un fichier de configuration local

Ce que nous traitons ici, c’est une conception réaliste pour « ne pas laisser en clair, dans appsettings.json, un secret qu’on est de toute façon obligé de stocker localement ». Il ne s’agit pas d’une « défense parfaite qui bat n’importe quel attaquant ». Trop en rajouter sur ce point, et un article de sécurité se transforme vite en histoire de fantômes.

1. La conclusion d’abord

En pratique, il est plus clair de raisonner dans cet ordre.

  1. Ne pas donner de secret de longue durée au client, pour commencer
    • Privilégier l’authentification Windows, l’authentification intégrée, la connexion interactive de l’utilisateur et la gestion des secrets côté serveur
  2. Si un stockage local est vraiment nécessaire, ne pas le laisser en clair
    • Sous Windows, faire de DPAPI / ProtectedData le premier choix
  3. Pour une application de bureau classique, partir sur DataProtectionScope.CurrentUser
    • LocalMachine n’a que des cas d’usage assez limités
  4. DPAPI ne protège pas jusqu’à « la machine est totalement compromise »
    • Un code exécuté avec les mêmes privilèges utilisateur peut, par nature, déchiffrer tout ce que cet utilisateur peut déchiffrer

Et le point le plus important de cet article se trouve ici :

« De toute façon, la clé secrète doit être stockée quelque part, alors d’un point de vue sécurité, le texte en clair et DPAPI ne reviennent-ils pas au même ? »

C’est à moitié vrai, mais la conclusion qu’on en tire est fausse.

  • Un chiffrement AES maison, avec la clé placée dans la même application ou la même configuration, reste effectivement très proche du texte en clair
  • Mais DPAPI délègue la gestion des clés au système d’exploitation et lie la partie capable de déchiffrer à « cet utilisateur Windows » ou à « cet ordinateur »
  • La résistance à des incidents comme une fuite isolée du fichier de configuration, son transport vers un autre PC, un envoi par erreur, une fuite de sauvegarde ou une intrusion dans un dépôt de code en est donc radicalement changée

Autrement dit : même si l’affirmation abstraite « la clé est quelque part » les fait paraître identiques, « qui peut l’utiliser, dans quel contexte, et avec quelle facilité » est totalement différent.

Dire que « poser la clé sous le paillasson » et « la remettre à l’accueil après vérification d’identité » reviennent au même, c’est un peu abusif.

2. Pourquoi une configuration en clair est dangereuse

La raison pour laquelle le stockage en clair est dangereux tient beaucoup moins à la théorie cryptographique qu’à des considérations très terre à terre. En pratique, les fuites empruntent généralement ces chemins :

  • Le fichier de configuration finit tel quel dans Git
  • Le fichier de configuration se retrouve intégralement dans un ZIP d’investigation d’incident
  • Une demande de support est envoyée avec le fichier de configuration en pièce jointe
  • Des tiers peuvent le lire via des sauvegardes ou des partages de fichiers
  • Les chaînes de connexion et les jetons apparaissent tels quels dans les journaux
  • Un employé parti ou un autre utilisateur peut lire le fichier sur la même machine

Le problème majeur du texte en clair, c’est que dès l’instant où il est lu, c’en est fini du secret.

  • Le fichier s’ouvre : c’est terminé
  • Il est copié : c’est terminé
  • Il est joint à un e-mail : c’est terminé
  • Il reste dans un dépôt : il faudra s’en occuper quasiment indéfiniment

L’attaquant n’a même pas besoin d’être sophistiqué. « Ça s’ouvre dans un éditeur de texte » suffit déjà à en faire une protection très faible.

3. Réponse à « la clé secrète est de toute façon stockée quelque part, alors n’est-ce pas la même chose ? »

Cette question est légitime. Et y répondre de façon approximative, c’est exactement ce qui rend un article de sécurité soudainement flou.

La réponse : oui, au sens où « une clé est nécessaire quelque part » ; non, au sens où cela rendrait les deux situations identiques.

3.1. Ce qui est identique et ce qui diffère

Il est vrai que le chiffrement a, in fine, besoin d’une racine de confiance (root of trust). Un secret ne jaillit pas gratuitement de nulle part dans l’univers. Ce monde-là ne fait pas de cadeaux.

Cependant, la différence en matière de sécurité se joue sur ces trois points :

  • L’application détient-elle la clé directement ?
  • À quelle partie la clé est-elle liée ?
  • Si seul le fichier est volé, peut-il être déchiffré ?

Un tableau grossier de ces différences donne ceci.

Méthode Le fichier de configuration est lu Seul le fichier est transporté vers un autre PC Lu par un autre utilisateur sur le même PC Code exécuté avec les mêmes privilèges utilisateur
Texte en clair Fuite immédiate Fuite telle quelle Fuite telle quelle Lisible, évidemment
Chiffrement maison + clé dans la même configuration / le même binaire Fuite quasi certaine Fuite quasi certaine Fuite quasi certaine Déchiffrable, évidemment
DPAPI + CurrentUser Pas directement lisible depuis le fichier seul Normalement difficile à déchiffrer Normalement difficile à déchiffrer Déchiffrable
DPAPI + LocalMachine Pas directement lisible depuis le fichier seul Normalement difficile à déchiffrer en dehors de ce PC Largement déchiffrable sur ce même PC Déchiffrable

Le point important ici est que DPAPI sépare « pouvoir lire le fichier » de « pouvoir utiliser le secret ».

Avec le texte en clair, ces deux choses n’en font qu’une. Si le fichier peut être lu, le secret peut l’être aussi.

Mais avec DPAPI - au moins avec CurrentUser - le déchiffrement doit se faire :

  • en tant que cet utilisateur Windows
  • dans ce contexte Windows précis
  • via le mécanisme de protection du système d’exploitation

Sur le terrain, au moment d’un incident, cette différence pèse lourd.

3.2. « Mais un même utilisateur peut quand même déchiffrer, non ? » - Exact

Ce point doit être écrit sans détour.

Un code exécuté avec les mêmes privilèges utilisateur peut, par nature, déchiffrer tout ce que cet utilisateur peut déchiffrer.

Autrement dit, DPAPI n’a pas pour objectif premier de couvrir des situations comme :

  • la machine est déjà compromise par un logiciel malveillant
  • l’attaquant peut exécuter du code en tant que cet utilisateur
  • la machine est totalement prise de contrôle au niveau administrateur

Dans ces situations, puisque l’application elle-même peut déchiffrer, le code de l’attaquant le peut aussi. Dans ce cas, un « mais c’est chiffré » n’est pas particulièrement rassurant.

DPAPI est surtout efficace du côté « fuite de fichier / erreur de placement / exfiltration hors ligne / accès par un autre utilisateur ».

Se tromper sur ce point mène à deux écueils :

  • sous-estimer ce qu’il protège et ne pas l’utiliser
  • surestimer ce qu’il ne protège pas et se croire en sécurité

Les deux sont dangereux, discrètement.

3.3. Alors, quel est le bénéfice concret ?

L’intérêt de DPAPI, en une phrase :

« Découpler le secret lui-même de la lisibilité du fichier de configuration. »

Par exemple, le texte en clair et DPAPI font une vraie différence dans des incidents comme ceux-ci :

  • un utilisateur a envoyé le fichier de configuration au support
  • le fichier de configuration s’est retrouvé dans un ZIP d’investigation
  • seul le fichier de configuration a fuité depuis une sauvegarde
  • il a été copié sur un dossier partagé
  • un développeur n’a vu que le texte chiffré, sans pouvoir en lire le contenu

Ce sont des bénéfices tout à fait concrets. On peut réduire le rayon des incidents du quotidien sans avoir besoin de transformer l’attaquant en surhomme de cinéma.

4. Pourquoi DPAPI tombe juste

Pour gérer des secrets stockés localement sous Windows, voici les raisons pour lesquelles DPAPI se situe exactement au bon endroit en pratique.

4.1. La gestion des clés peut être déléguée à l’OS

Générer soi-même une clé AES, la stocker, lui attribuer des permissions, la faire tourner, réfléchir à l’impact d’une fuite, et ajouter une détection de falsification. C’est plus lourd qu’il n’y paraît. Et fait à la légère, cela finit généralement par placer la clé au même endroit que le reste.

Avec DPAPI, le problème « comment créer la clé de chiffrement et où la placer » peut être retiré de l’implémentation de l’application.

En ce sens, il est plus juste de voir DPAPI comme « une API qui délègue la gestion des clés au système d’exploitation » plutôt que comme « une API permettant de choisir un algorithme de chiffrement ».

4.2. La partie qui déchiffre peut être liée à un utilisateur Windows ou à l’ordinateur

Pour une application de bureau classique, choisir CurrentUser est souvent le bon réflexe.

Le déchiffrement suppose alors :

  • que cet utilisateur soit connecté
  • que le traitement s’exécute dans le contexte de cet utilisateur

On obtient ainsi la propriété que copier uniquement le texte chiffré vers un autre PC ne le rend pas directement exploitable.

4.3. La détection de falsification vient facilement avec

Une erreur fréquente avec un chiffrement maison est de se dire « on a chiffré avec AES, c’est terminé » et d’oublier la détection de falsification.

DPAPI apporte aussi une protection de l’intégrité sur les données chiffrées, ce qui fait que la détection d’une réécriture du texte chiffré peut s’appuyer sur le mécanisme côté OS - un avantage bien concret en pratique.

4.4. Simple à utiliser depuis C# / .NET

En C#, on peut utiliser directement System.Security.Cryptography.ProtectedData. Ne pas avoir à ajouter de bibliothèque supplémentaire est un vrai confort pour une application réservée à Windows.

5. Ce que DPAPI protège, et ce qu’il ne protège pas

Il est plus sûr de tracer clairement cette limite.

5.1. Ce qui devient plus facile à protéger

DPAPI est efficace, au moins, dans des situations comme celles-ci :

  • fuite en clair d’un fichier de configuration
  • fichier transporté vers un autre PC
  • accès par un autre utilisateur sur le même PC (en supposant CurrentUser)
  • fuite via une sauvegarde ou une pièce jointe
  • l’état « ah, ça se lit sans faire attention » qu’on rencontre en développement ou en maintenance

5.2. Ce qu’il ne protège pas, ou protège mal

À l’inverse, il vaut mieux ne pas trop lui faire confiance dans les situations suivantes :

  • du code malveillant exécuté avec les mêmes privilèges utilisateur
  • une compromission complète de la machine elle-même
  • une prise de contrôle au niveau administrateur
  • le texte en clair en mémoire une fois que l’application a déchiffré la valeur
  • un secret de longue durée distribué à l’identique sur tous les clients

Ce dernier point - « un secret de longue durée commun à tous les clients » - est particulièrement important.

Par exemple, des conceptions comme :

  • intégrer la même clé API pour tous les clients
  • partager le même mot de passe sur toutes les machines
  • distribuer une clé de déchiffrement fixe qui vit entièrement côté client

sont des conceptions où l’extraction depuis une seule machine tend à se répercuter sur l’ensemble.

DPAPI est efficace pour « rendre cet emplacement de stockage meilleur que le texte en clair », mais il ne justifie en rien des secrets qui ne devraient tout simplement pas se trouver côté client.

6. Choisir entre CurrentUser et LocalMachine

Ce point compte énormément. Un choix fait à la légère change radicalement la portée de la protection.

6.1. CurrentUser par défaut

Pour une application de bureau Windows classique, il faut d’abord raisonner en partant de CurrentUser.

Cas bien adaptés :

  • applications de bureau WPF / WinForms / WinUI destinées aux utilisateurs
  • applications qui ont des paramètres et des identifiants par utilisateur
  • applications qui conservent leurs paramètres sous %LocalAppData% ou %AppData%

Dans ce cas, il devient naturel de traiter la donnée comme « le secret de cet utilisateur Windows ».

6.2. LocalMachine : des cas d’usage assez limités

LocalMachine paraît pratique, mais pour une application de bureau ordinaire, il est trop large.

Il convient plutôt à des cas comme :

  • un service Windows sur une machine de confiance dédiée à un seul usage
  • un secret utilisé uniquement par un processus précis sur cette machine
  • des cas qui doivent réellement fonctionner à travers plusieurs utilisateurs connectés sur la même machine

Mais les précautions à prendre sont lourdes.

  • Il est largement déchiffrable par les processus qui tournent sur ce PC
  • Il devient facilement dangereux sur les machines partagées, les hôtes RDS, les machines rebond et les environnements multi-utilisateurs
  • Le choisir « pour que tout le monde puisse s’en servir facilement » finit généralement par poser problème plus tard

6.3. En cas de doute, raisonner ainsi

  • Application UI classique -> CurrentUser
  • Cas particulier où l’on veut vraiment protéger au niveau de la machine -> LocalMachine
  • Il faut que n’importe quel utilisateur puisse déchiffrer, mais d’autres utilisateurs sont présents sur la machine -> il vaut généralement mieux revoir la conception elle-même

6.4. Les services et l’impersonation demandent un peu plus de vigilance

Dès qu’on mêle des services Windows ou de l’impersonation, la portée de CurrentUser devient un peu plus lourde à cerner.

  • Quel est le compte d’exécution ?
  • Le profil de ce compte est-il chargé ?
  • Dans quel contexte se produit le déchiffrement ?

Un décalage sur ces points aboutit facilement à « ça a chiffré correctement, mais ça ne déchiffre pas ». Pour un usage de type service, se contenter de « CurrentUser par défaut » ne suffit pas toujours.

7. Consignes minimales d’implémentation

Si l’objectif se limite à « arrêter de stocker en clair dans le fichier de configuration » d’une application Windows, la conception n’a pas besoin d’être très complexe. Il y a néanmoins quelques points qu’on ne veut pas manquer.

7.1. Ne protéger que les secrets

Plutôt que de chiffrer l’ensemble de la configuration en bloc, il est plus simple de gérer les choses si l’on protège uniquement les éléments secrets.

Par exemple, on peut séparer ainsi. Ceux-ci peuvent souvent rester en clair :

  • URL du serveur
  • nom d’utilisateur
  • nom de la base de données
  • indicateurs de fonctionnalités (feature flags)

Alors que ceux-ci sont à protéger :

  • mots de passe
  • jetons API
  • jetons de rafraîchissement (refresh tokens)
  • identifiants de dossiers partagés

Avec ce découpage, on gagne :

  • une édition de la configuration plus facile
  • une revue de différences plus facile
  • une clarté sur ce qui est secret
  • une exploitation globale plus simple

7.2. Stocker par défaut dans un emplacement par utilisateur

Pour une application de bureau classique, l’emplacement de stockage par défaut doit être un emplacement par utilisateur.

  • %LocalAppData%\Vendor\App\settings.json
  • %AppData%\Vendor\App\settings.json

Au minimum, il vaut mieux ne pas le placer négligemment sous le dossier d’installation ou dans un endroit facile à partager.

Même protégé par DPAPI, si les ACL de l’emplacement de stockage sont négligées, on retombe sur « le texte chiffré peut être lu », « la structure de la configuration reste visible », « des erreurs d’exploitation se produisent ». La défense fonctionne mieux en couches successives que sur un seul niveau.

7.3. optionalEntropy n’est pas une seconde clé miracle

ProtectedData permet de passer un optionalEntropy. C’est pratique, mais ce n’est pas « une seconde clé magique qui rend tout sûr dès qu’on l’intègre dans le binaire ».

  • La placer dans le même fichier n’en fait pas un secret
  • L’intégrer comme valeur fixe dans le binaire n’en fait pas non plus un secret solide
  • Cela reste tout de même utile pour identifier l’usage et éviter les erreurs de réutilisation

En pratique, faire passer une suite d’octets fixe construite à partir :

  • du nom de l’application
  • du nom de l’usage
  • d’un identifiant de version

et l’utiliser « pour éviter d’accepter par erreur un texte chiffré destiné à un autre usage » est à peu près le bon niveau d’ambition.

7.4. Cela ne veut pas dire que le texte chiffré peut aller dans Git

Ce point aussi est discrètement important.

Le texte chiffré par DPAPI est bien meilleur que le texte en clair, mais cela ne veut pas dire que le fichier de configuration entier peut aller dans le dépôt.

Les raisons sont simples :

  • le texte chiffré reste en place longtemps
  • la même machine ou le même contexte pourrait un jour se reproduire
  • le fichier contient aussi des informations autres que le secret
  • une culture du « c’est protégé, donc on peut être négligent » finit par s’installer

« Meilleur que le texte en clair » et « sûr n’importe où on le place » sont deux choses complètement différentes.

7.5. Ne pas l’écrire dans les journaux

Un schéma étonnamment courant consiste à tout gâcher en écrivant la valeur dans les journaux après déchiffrement.

  • afficher intégralement la chaîne de connexion en cas d’échec de connexion
  • laisser l’en-tête Authorization dans les journaux lors d’une erreur API 401
  • mélanger des secrets dans les messages d’exception

Faites cela, et même après avoir éliminé le texte en clair du fichier de configuration, ce sont finalement les journaux qui deviennent l’entrepôt du texte en clair. Triste, mais très réel sur le terrain.

8. Exemple d’implémentation minimale en C# / .NET

Voici un exemple minimal protégeant, avec CurrentUser, une chaîne destinée à être enregistrée dans un fichier de configuration. Un optionalEntropy fixe y figure pour l’identification de l’usage, mais ne le considérez surtout pas comme une clé secrète.

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

public static class DpapiSecretProtector
{
    // Pour l'identification de l'usage. Ce n'est pas une seconde clé secrète.
    private static readonly byte[] Entropy =
        Encoding.UTF8.GetBytes("ComComponent:DesktopApp:SettingsSecret:v1");

    public static string ProtectToBase64(string plaintext)
    {
        ArgumentNullException.ThrowIfNull(plaintext);

        byte[] plainBytes = Encoding.UTF8.GetBytes(plaintext);
        byte[] protectedBytes = Array.Empty<byte>();

        try
        {
            protectedBytes = ProtectedData.Protect(
                plainBytes,
                optionalEntropy: Entropy,
                scope: DataProtectionScope.CurrentUser);

            return Convert.ToBase64String(protectedBytes);
        }
        finally
        {
            Array.Clear(plainBytes, 0, plainBytes.Length);

            if (protectedBytes.Length > 0)
            {
                Array.Clear(protectedBytes, 0, protectedBytes.Length);
            }
        }
    }

    public static string UnprotectFromBase64(string protectedBase64)
    {
        ArgumentNullException.ThrowIfNull(protectedBase64);

        byte[] protectedBytes = Convert.FromBase64String(protectedBase64);
        byte[] plainBytes = Array.Empty<byte>();

        try
        {
            plainBytes = ProtectedData.Unprotect(
                protectedBytes,
                optionalEntropy: Entropy,
                scope: DataProtectionScope.CurrentUser);

            return Encoding.UTF8.GetString(plainBytes);
        }
        finally
        {
            Array.Clear(protectedBytes, 0, protectedBytes.Length);

            if (plainBytes.Length > 0)
            {
                Array.Clear(plainBytes, 0, plainBytes.Length);
            }
        }
    }
}

L’usage est simple.

string protectedPassword = DpapiSecretProtector.ProtectToBase64(password);

// Enregistrer dans un JSON, etc.
// settings.DbPasswordProtected = protectedPassword;

string password = DpapiSecretProtector.UnprotectFromBase64(settings.DbPasswordProtected);

Le fichier de configuration peut alors prendre une forme comme celle-ci.

{
  "ApiBaseUrl": "https://api.example.com/",
  "UserName": "app-user",
  "PasswordProtected": "AQAAANCMnd8BFdERjHoAwE..."
}

Ce qui rend cette forme intéressante :

  • l’URL et le nom d’utilisateur restent modifiables normalement
  • seul le mot de passe est protégé
  • la structure de la configuration reste lisible
  • c’est moins propice aux incidents que de tout laisser en clair

9. Des conceptions qui restent dangereuses

Même en utilisant DPAPI, les conceptions suivantes restent dangereuses.

9.1. Conserver la valeur déchiffrée trop longtemps

Il vaut mieux éviter de prendre la valeur déchiffrée et de :

  • l’écrire dans les journaux
  • l’afficher à l’écran
  • l’inclure dans une exception
  • la laisser traîner sur un objet à durée de vie longue

« Chiffré au repos » et « sûr pendant l’utilisation » sont deux problèmes distincts.

9.2. Donner un secret commun à toutes les installations

Par exemple, une conception où tous les utilisateurs détiennent la même clé API n’est pas réellement résolue en la stockant via DPAPI.

Car si l’application peut la déchiffrer sur une seule machine, ce secret peut en être extrait à cet endroit-là.

Ce type de secret gagne à être orienté vers :

  • un stockage côté serveur
  • un client qui ne détient que des jetons
  • des identifiants par utilisateur
  • des jetons à durée limitée

9.3. Choisir LocalMachine « parce que c’est plus simple »

C’est vraiment un cas fréquent.

On est tenté de choisir LocalMachine parce que :

  • ça reste lisible même après un changement d’utilisateur
  • un service peut aussi le lire
  • c’est pratique tant que ça fonctionne

Mais pour une application de bureau ordinaire, cela étend la possibilité de déchiffrement à d’autres processus présents sur ce PC, ce qui change considérablement la portée de la protection.

9.4. Se rassurer en ajoutant un chiffrement maison

Au lieu de DPAPI, des implémentations comme :

  • intégrer une clé AES dans le code source
  • placer la clé AES dans un autre champ du fichier de configuration
  • traiter une « chaîne de caractères un peu obfusquée » comme une clé

sont généralement de peu d’effet.

Entre « ce n’est pas en clair » et « c’est sûr », il existe un fossé assez large.

10. Les cas où DPAPI ne suffit pas

DPAPI est pratique, mais il n’est pas la panacée. Dans les cas suivants, mieux vaut envisager une autre option.

10.1. Vous voulez fonctionner aussi hors de Windows

DPAPI / ProtectedData sont réservés à Windows. Une application multiplateforme ne peut pas s’appuyer sur cette hypothèse.

10.2. Vous voulez partager le même secret entre plusieurs machines ou utilisateurs

Un besoin de déchiffrer le même texte chiffré sur plusieurs PC, ou de le mutualiser entre plusieurs utilisateurs, sort du domaine de prédilection de DPAPI, qui lie le secret « à cette machine, à cet utilisateur ».

Dans ce cas, il faut plutôt envisager une conception adaptée au besoin, comme :

  • une gestion des secrets côté serveur
  • une infrastructure d’identifiants
  • l’authentification Windows / l’authentification intégrée
  • un magasin d’identifiants dédié à l’application

10.3. Ce qui est stocké est directement des identifiants utilisateur

Pour une application de bureau packagée / de type WinUI, si ce qui est stocké est clairement une paire :

  • nom d’utilisateur
  • mot de passe

le Credential Locker devient également une option. Mais le cœur de cet article reste la ligne de base pratique de DPAPI pour « arrêter le texte en clair dans les fichiers de configuration des clients Windows ».

11. Ordre de priorité recommandé en pratique

Pour finir, en cas d’hésitation en pratique, raisonner dans cet ordre permet d’y voir clair.

Priorité 1 : ne pas le détenir du tout

  • authentification Windows
  • authentification intégrée
  • connexion interactive
  • conservation du secret côté serveur
  • jetons de courte durée

Priorité 2 : privilégier des secrets par utilisateur

  • privilégier le par-utilisateur plutôt qu’un secret commun
  • privilégier des jetons renouvelables plutôt que des identifiants fixes de longue durée
  • éviter une clé commune à tous les clients

Priorité 3 : si un stockage local est nécessaire, DPAPI

  • CurrentUser en règle générale
  • un emplacement de stockage par utilisateur
  • ne protéger que les éléments secrets
  • ne pas les écrire dans les journaux

Priorité 4 : traiter LocalMachine comme une exception

  • est-ce vraiment nécessaire au niveau de la machine ?
  • d’autres utilisateurs se connectent-ils sur cette machine ?
  • est-ce cohérent en tant que conception de service ?

12. Résumé

Lorsqu’une application Windows doit stocker des informations sensibles dans un fichier de configuration, mieux vaut éviter de les laisser en clair.

Et à la question :

« De toute façon, la clé est stockée quelque part, alors n’est-ce pas la même chose ? »

la réponse pratique est la suivante :

  • avec un chiffrement maison où la clé est placée au même endroit, c’est effectivement quasiment la même chose
  • DPAPI, en revanche, n’est pas la même chose
    • la gestion des clés peut être déléguée à l’OS
    • la partie qui déchiffre peut être liée à un utilisateur Windows / un ordinateur
    • une fuite isolée du fichier n’équivaut plus directement à une fuite du secret
  • cela dit, cela ne résout pas :
    • le cas d’un code exécuté avec les mêmes privilèges utilisateur
    • le cas d’une machine totalement compromise
    • le cas de secrets communs de longue durée qui ne devraient tout simplement pas se trouver côté client

En somme, DPAPI n’est pas une forteresse infranchissable. Mais il a à peu près l’effet de remplacer la vitre grande ouverte qu’est une configuration en clair par au moins une fenêtre décente.

Dans le travail quotidien sur des clients Windows, cette différence est considérable. Commencer par bien traiter ce point est l’approche la plus réaliste.

13. Références

  • Article précédent : https://comcomponent.com/fr/blog/2026/03/14/001-windows-app-security-minimum-checklist/
  • Microsoft Learn : CryptProtectData https://learn.microsoft.com/en-us/windows/win32/api/dpapi/nf-dpapi-cryptprotectdata
  • Microsoft Learn : ProtectedData https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.protecteddata?view=windowsdesktop-10.0
  • Microsoft Learn : DataProtectionScope https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.dataprotectionscope?view=windowsdesktop-10.0
  • Microsoft Learn : How to: Use Data Protection https://learn.microsoft.com/en-us/dotnet/standard/security/how-to-use-data-protection
  • Microsoft Learn : Credential locker for Windows apps https://learn.microsoft.com/en-us/windows/apps/develop/security/credential-locker

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

Ce sujet touche à la conception globale d'une application Windows - la façon de stocker les identifiants, l'emplacement des paramètres par utilisateur et ce qui doit ou non apparaître dans les journaux - il s'accorde donc bien 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.

Qu'est-ce que DPAPI ?
DPAPI (Data Protection API) est un mécanisme de protection des données fourni par Windows : il délègue la gestion des clés de chiffrement au système d'exploitation et lie la partie capable de déchiffrer à cet utilisateur Windows précis ou à cet ordinateur précis. Depuis C# / .NET, on l'utilise via la classe System.Security.Cryptography.ProtectedData, sans avoir à ajouter de bibliothèque supplémentaire. Il est plus juste de le voir non pas comme une API permettant de choisir un algorithme de chiffrement, mais comme une API qui délègue la gestion des clés au système d'exploitation. C'est une option réaliste pour éviter de laisser en clair, dans un fichier de configuration, les mots de passe ou les jetons API.
La clé doit bien être stockée quelque part, alors le texte en clair et DPAPI ne reviennent-ils pas au même ?
Non, ce n'est pas la même chose. Un chiffrement AES maison, avec la clé placée dans la même application ou le même fichier de configuration, reste effectivement très proche du texte en clair. Mais DPAPI délègue la gestion des clés au système d'exploitation et lie la partie capable de déchiffrer à un utilisateur Windows ou à un ordinateur donné. La résistance à des incidents comme une fuite isolée du fichier de configuration, son transport vers un autre PC, un envoi par erreur, une fuite de sauvegarde ou une intrusion dans un dépôt de code s'en trouve donc radicalement changée. La différence décisive avec le texte en clair, c'est que DPAPI sépare « pouvoir lire le fichier » de « pouvoir utiliser le secret ».
Que DPAPI ne protège-t-il pas ?
Un code exécuté avec les mêmes privilèges utilisateur peut, par nature, déchiffrer tout ce que cet utilisateur peut déchiffrer. DPAPI ne protège donc pas contre une machine déjà compromise par un logiciel malveillant, une prise de contrôle au niveau administrateur, ni contre le texte en clair présent en mémoire une fois le secret déchiffré. De même, un secret de longue durée distribué à l'identique sur tous les clients n'est pas réellement résolu par un stockage via DPAPI, car son extraction depuis une seule machine suffit à compromettre l'ensemble. DPAPI est surtout efficace du côté des fuites de fichiers, des erreurs de placement, de l'exfiltration hors ligne et de l'accès par un autre utilisateur.
Faut-il utiliser CurrentUser ou LocalMachine pour DataProtectionScope ?
Pour une application de bureau Windows classique, CurrentUser est le choix par défaut : le secret est alors traité comme appartenant à cet utilisateur, et copier uniquement le texte chiffré vers un autre PC ne le rend pas directement exploitable. LocalMachine, lui, peut être déchiffré largement par les processus qui tournent sur ce PC, ce qui devient risqué sur les machines partagées ou les environnements multi-utilisateurs ; ses cas d'usage restent donc assez limités, par exemple un service Windows sur une machine de confiance dédiée à un seul usage. Choisir LocalMachine parce que « tout le monde peut s'en servir, c'est plus simple » finit généralement par poser problème plus tard.

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