40

Windows PC に平文のパスワードを安全に保存したい。現在、DPAPICryptProtectDataを使用して暗号化し、暗号化された BLOB をユーザーのローカル AppData のファイルに保存しています。

Windows 7 には、「一般的な資格情報」を含むさまざまな種類のログオンのログオン データを格納する資格情報マネージャー (コントロール パネル\ユーザー アカウントと家族の安全\資格情報マネージャー) である Windows Vault があります。一見すると、これはプログラムが資格情報を保存するのに適した場所のように見えます。ただし、そのための API を見つけることができませんでした。MSDN で認証関数のリファレンスを読みましたが、率直に言って迷ってしまいました。

プログラムから資格情報を保存および取得するための Windows Vault への API はありますか? また、ある場合、ドキュメントはどこにありますか?

4

3 に答える 3

48

ヒントを提供してくれた @Luke に感謝します。資格情報を Windows Vault に保存して読み取る Windows API 関数はCredWrite()CredRead(). 以下は、これらの関数が実際に期待どおりの動作をすることを確認するために使用した、コンパイルして実行できるコード サンプルです。

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

int 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);
        // Memory allocated by CredRead() must be freed!
        ::CredFree (pcred);
    }
}

スクリーンショットに示すように、一般的な資格情報は Windows Vault に保存されます。

Windows Vault に保存されている一般的な資格情報

補遺: Vault vs Crypto DP API

この回答は非常に人気があるようで、私が書いてから 6 年近く定期的に支持されています。::CryptProtectData()資格情報をボールトに保存することと、 API を使用して資格情報 BLOB を暗号化し、必要なときにいつでも保存することの違いについて、コメントで提起された質問がありました。主な違いについての私の理解は、おそらく網羅的ではありませんが、次のとおりです。

  • ローミング制御。Vault 内のストレージは、システムによって管理されます。ドメイン環境では、この設定cred.Persist = CRED_PERSIST_ENTERPRISE;により、暗号化された資格情報がユーザーのローミング プロファイルの一部になるため、任意のドメイン コンピューターにログオンしているユーザーが利用できるようになります。CryptProtectData()データのみを暗号化します。暗号文の保管はユーザーの責任です。%APPDATA%ドメインのローミング設定によっては、暗号文を下に保存するとローミングも可能になりますが、ファイルに適切な ACL を設定し、EFS で保存時の暗号化を強制することは、やはり呼び出し元の責任です。ボールト データは、保存時にシステムによって暗号化されます。
  • UI の可視性。Vault の資格情報は Vault の UI に表示され、不要になった場合や侵害された疑いがある場合は取り消すことができます。から取得した暗号文CryptProtectData()は、アプリケーションによって完全に制御されます。ターゲット ソフトウェアの設計では、可視性機能を考慮する必要があります。
  • Vault は、メモリに暗号化されて格納される揮発性のログオン セッションごとのシークレットをサポートします ( cred.Persist = CRED_PERSIST_SESSION;)。ジェネリック API を使用したこのような機能の実装は、認証された IPC や同期を伴う正しく保護された共有メモリ マッピングなどを含むため、適切に実装するのは比較的困難です。
  • 塩漬け。の場合CryptProtectData()、呼び出し元は追加のソルトを提供できます (復号化中に再度提供する必要があるため、保存する手段があります)。Vault が内部的に処理します。
  • Vault の範囲はより狭いです。ID に関係のないデータの保存に Vault を使用するのは、おそらく設計上の臭いです。
  • 監査。CryptProtectData()BLOB が復号化されるときの監査レコードの作成を制御できます (CRYPTPROTECT_AUDITビット フラグ)。Vault API でこのようなものを確認できません ( wincred.h)。Vault アクセスの監査が可能かどうかはわかりません。常に実行されるか、実行されないか、GPO によって制御されるか。実際、私はここで空白を描いています。
  • Vault はHVCI (旧称Device Guard ; Windows 10/11 Pro および Enterprise でのみ利用可能、および対応するサーバー SKU) によって保護されます。有効にすると、システムの保護された部分は、別の準仮想化され、ハードウェアでサポートされ、厳密に制御されたアドレス空間で実行されます。このアドレス空間は、通常のアドレス空間には単に「存在しません」 (HVCI で保護された空間は、LSA およびその他の重要なコンポーネントが存在する場所です)。ライブもあります)。これにより、カーネル モード スタックからでもアクセスできなくなります。CNGプロバイダーもそのコンパートメントに住んでいますがCryptProtectData()、暗号文ブロブが呼び出し元のプログラムに返されると、結果は必然的にこの境界を越えます(また、CryptProtectData()CNGによってサポートされているかどうかもわかりません)。Vault で暗号化されたデータは、保護された境界内にとどまります。クリアテキストのみが交差します。

要約すると、Vault は、システム UI を介して管理され、ユーザーに表示され、ユーザーが管理する資格情報やその他の ID 関連の秘密を保持するための、より高レベルで対象を絞った API です。CryptProtectData()永続化された暗号文を安全に管理するために、より多くの柔軟性とより多くのコードを作成および監査する必要がある汎用暗号化 API です。

どちらが「より安全」であるかという問題は不適切です。全般的な暗号化の使用に適用できる「多かれ少なかれ安全」の定義はありません。

于 2012-02-10T12:53:05.260 に答える
18

スレッドに遅れて参加する人のために、Windows 8 のこのストアと対話するための新しいライブラリがあります。Windows.Security.Credentials.PasswordVault

実際、クラスを使用して現在のユーザー アカウントに保存されているすべてのユーザー名とパスワードを表示するには、2 行の powershell だけが必要です。

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

更新: Microsoft は (ありがたいことに) Windows 10 でこの API をさらに制限したようで、すべてのパスワードを簡単にダンプすることはなくなりました。これは、私が見た変化を示しているだけです。

ロッカーの内容は、アプリまたはサービスに固有です。アプリやサービスは、他のアプリやサービスに関連付けられた資格情報にアクセスできません。

于 2013-12-20T02:32:14.190 に答える
10

PowerShell または C# から読み書きすることに興味がある人は、それを行うスクリプトへのリンクを次に示します。

PowerShell Credentials Manager: CredMan.ps1 (archive.org 経由)

PowerShell スクリプトは、Pinvoke を利用するインライン C# を介して API にアクセスします。

于 2013-08-29T13:46:58.133 に答える