web-dev-qa-db-fra.com

Comment stocker et récupérer des informations d'identification à partir du gestionnaire d'informations d'identification Windows Vault?

Je souhaite stocker en toute sécurité un mot de passe en clair sur un PC Windows. J'utilise actuellement DPAPI CryptProtectData pour le crypter, puis stocke le blob crypté dans un fichier dans l'AppData local de l'utilisateur.

Dans Windows 7, il existe Windows Vault, un gestionnaire d'informations d'identification (Panneau de configuration\Comptes d'utilisateurs et Family Safety\Credential Manager) qui stocke les données d'ouverture de session pour une variété de types d'ouverture de session, y compris les "informations d'identification génériques". En apparence, cela semble être le bon endroit pour un programme pour stocker les informations d'identification. Cependant, je n'ai pu trouver aucune API pour cela. J'ai lu Fonction d'authentification référence dans MSDN, mais franchement je me suis perdu dedans.

Existe-t-il une API pour Windows Vault pour stocker et récupérer les informations d'identification d'un programme et, si oui, où puis-je trouver de la documentation?

32
kkm

Un grand merci à @Luke pour l'astuce: les fonctions de l'API Windows pour stocker les informations d'identification et les lire à partir de Windows Vault sont CredWrite() et CredRead() . Voici un exemple de code qui peut être compilé et exécuté, que j'ai utilisé pour confirmer que ces fonctions font effectivement la chose attendue:

#include <windows.h>
#include <wincred.h>
#include <tchar.h>
#pragma hdrstop

void main ()
{
    { //--- SAVE
        char* password = "brillant";
        DWORD cbCreds = 1 + strlen(password);

        CREDENTIALW cred = {0};
        cred.Type = CRED_TYPE_GENERIC;
        cred.TargetName = L"FOO/account";
        cred.CredentialBlobSize = cbCreds;
        cred.CredentialBlob = (LPBYTE) password;
        cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
        cred.UserName = L"paula";

        BOOL ok = ::CredWriteW (&cred, 0);
        wprintf (L"CredWrite() - errno %d\n", ok ? 0 : ::GetLastError());
        if (!ok) exit(1);
    }
    { //--- RETRIEVE
        PCREDENTIALW pcred;
        BOOL ok = ::CredReadW (L"FOO/account", CRED_TYPE_GENERIC, 0, &pcred);
        wprintf (L"CredRead() - errno %d\n", ok ? 0 : ::GetLastError());
        if (!ok) exit(1);
        wprintf (L"Read username = '%s', password='%S' (%d bytes)\n", 
                 pcred->UserName, (char*)pcred->CredentialBlob, pcred->CredentialBlobSize);
        // must free memory allocated by CredRead()!
        ::CredFree (pcred);
    }
}

Un identifiant générique est stocké dans Windows Vault, comme on peut le voir sur la capture d'écran:

A generic credential stored in Windows Vault

33
kkm

Pour les personnes qui rejoignent le fil en retard, il existe une nouvelle bibliothèque pour interagir avec ce magasin dans Windows 8 appelée: Windows.Security.Credentials.PasswordVault

En fait, il suffit de deux lignes de PowerShell pour utiliser la classe pour afficher tous les noms d'utilisateur et mots de passe stockés sous le compte utilisateur actuel:

[void][Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime]
(new-object Windows.Security.Credentials.PasswordVault).RetrieveAll() | % { $_.RetrievePassword(); $_ }

( Mise à jour: Il semble que Microsoft (heureusement) restreigne davantage cette API dans Windows 10 et ne supprimera plus tous vos mots de passe si trivialement. Ce n'est qu'une indication du changement que j'ai vu:

Le contenu du casier est spécifique à l'application ou au service. Les applications et services n'ont pas accès aux informations d'identification associées à d'autres applications ou services.

16
Tim

Si quelqu'un est intéressé à y lire et à y écrire à partir de PowerShell ou C #, voici un lien vers un script qui le fait:

Gestionnaire d'informations d'identification PowerShell: CredMan.ps1

Le script PowerShell accède à l'API via C # en ligne qui utilise Pinvoke.

7
Tim Lewis