メインコンテンツまでスキップ

Windows実行ファイルでAPIキーをどう保持するか

対象

本稿は、Windows向けのデスクトップ実行ファイルでAPIキーをローカル保持する場合の実装方式を比較する。対象は次の5方式に限定する。

  • 実行ファイルへのコード埋め込み
  • 平文ファイル保存
  • DPAPI
  • Credential Manager
  • Credential Locker(PasswordVault

ここで比較するのは、ローカル保存時の保護方式である。サーバ経由設計、OAuthフロー、トークン短寿命化、通信路保護は扱わない。

要点

  • 配布型のWindows実行ファイルに共通APIキーを埋め込む方式は、秘密保持方式としては成立しにくい。RFC 8252は、複数ユーザーに配布されるネイティブアプリに静的に含まれる共有シークレットを、機密として扱うべきではないとしている。1
  • 平文ファイル保存は実装が最も容易だが、秘密情報の保存方式としては避けるべきである。NIST SP 800-57 Part 2は、秘密鍵や秘密メタデータを暗号モジュール外に保存する場合、少なくとも機密性と完全性の保護を要件化している。MicrosoftもCredential Lockerのベストプラクティスで、資格情報を平文で保存しないよう明記している。23
  • DPAPIは「任意のバイト列をOSに保護させる方式」であり、保存先はアプリ側が管理する。Windowsデスクトップアプリでは扱いやすく、APIキー1件や少数の秘密情報を保護する用途に向く。456
  • Credential Managerは「OS管理の資格情報ストアに汎用資格情報として格納する方式」であり、Win32デスクトップアプリとの親和性が高い。APIキーが1件の文字列として表現できるなら、DPAPIより実装が簡潔になることが多い。789
  • Credential LockerはWinRTのPasswordVaultによる資格情報保管方式で、UWP/WinUI/パッケージ化デスクトップアプリ寄りのAPIである。Microsoftはパスワード向けの利用を前提に説明しており、一般的なWin32実行ファイルの第一候補とは言いにくい。310

評価軸

本稿では、次の観点で比較する。

  • 配布物解析に対する強さ
  • ローカルファイル持ち出しに対する強さ
  • 同一Windowsユーザー権限で動く別プロセスに対する強さ
  • 実装のしやすさ
  • Windowsデスクトップアプリとの適合性

なお、同一ユーザー権限で動作する不正プロセスへの耐性は、DPAPI / Credential Manager / Credential Locker のいずれでも限定的とみなすべきである。
これは、Microsoft文書がそれぞれ CurrentUsercurrent token のログオンセッション、user-specific なロッカーという単位でアクセス境界を定義しているためである。これは文書上のアクセス境界からの評価であり、本稿の推論を含む。6810

1. コード埋め込み

コード埋め込みの方式

APIキーを、EXE/DLL本体、リソース、定数テーブル、設定の初期値などに直接埋め込む。

コード埋め込みの特性

  • 配布物だけで完結するため、実装は最も簡単
  • 初回設定やユーザー入力が不要
  • ただし、秘密情報は配布物の一部になる

RFC 8252は、複数ユーザーに配布されるネイティブアプリに静的に含まれる共有シークレットは、機密として扱うべきではないと整理している。1
この考え方はOAuthクライアントシークレットの文脈だが、配布済みネイティブアプリに共通秘密を持たせる設計一般にもそのまま当てはまる。

コード埋め込みの評価

  • 配布物解析に弱い
  • ローテーション時に再配布が必要になりやすい
  • 共通キーを入れると、1件の漏えいが全利用者に波及しやすい

コード埋め込みが向くケース

  • 機密ではない識別子
  • 公開前提のclient_id
  • サンプルコードや検証用の一時実装

機密なAPIキーの保持方式としては不適切である。

2. 平文ファイル保存

平文ファイル保存の方式

APIキーをjsonini、SQLite、レジストリなどに平文のまま保存する。

平文ファイル保存の特性

  • 実装が容易
  • 外部編集やサポートが容易
  • バックアップ、同期、誤送信、端末共有、スクリーンショットなどで露出しやすい

NIST SP 800-57 Part 2は、秘密情報を暗号モジュール外に保存する場合、完全性を保護し、秘密情報の機密性も保護すべきとする。高・中インパクトの情報では暗号学的保護を要求している。2
またMicrosoftはCredential Lockerのベストプラクティスとして、資格情報をアプリデータやローミング設定に平文保存しないよう明記している。3

平文ファイル保存の評価

  • 配布物解析よりはましだが、ファイル入手だけで読める
  • OSのファイルACLに依存しやすい
  • 監査上も説明しにくい

平文ファイル保存が向くケース

  • 開発環境限定の一時用途
  • 非機密情報

本番用の機密APIキーには不適切である。

3. DPAPI

DPAPIの方式

WindowsのData Protection APIで、アプリが平文をOSに渡し、暗号化済みのBLOBを受け取る。Win32ではCryptProtectData / CryptUnprotectData、.NETではProtectedDataから利用できる。45

DPAPIに関するMicrosoft文書上のポイント

  • CryptProtectDataは平文DATA_BLOBを暗号化する。4
  • 通常は、暗号化したユーザーと同じログオン資格情報を持つユーザーだけが復号できる。4
  • CRYPTPROTECT_LOCAL_MACHINEを使うと、同じコンピューター上の任意のユーザーが復号できる。4
  • DPAPIは改ざん検知のためにMACを付与する。4
  • .NETのProtectedDataはDPAPIのラッパーであり、CurrentUserLocalMachineのスコープを選べる。LocalMachineは「そのコンピューター上の任意のプロセスが復号できる」ため、Microsoftは通常CurrentUserの利用を推奨している。56

DPAPIの実装上の意味

DPAPIは保存場所そのものではなく保護手段である。
つまり、実装は通常次の形になる。

  1. APIキーをCryptProtectDataまたはProtectedData.Protectで暗号化する
  2. 返ってきた暗号化BLOBをファイル、レジストリ、ローカルDBなどに保存する
  3. 必要時に復号する

DPAPIの利点

  • Win32/.NETデスクトップアプリで使いやすい
  • 任意のバイト列を保護できる
  • アプリが独自の暗号鍵を保持しなくてよい
  • CurrentUserを使えば、別ユーザーによる単純なファイル持ち出しに強い

DPAPIの制約

  • 暗号化済みデータの保管場所、命名、削除、バックアップはアプリ側の責務
  • LocalMachineはクライアント端末では広すぎることが多い
  • Microsoftは、ユーザープロファイルが読み込まれていない状態や偽装実行時には復号で問題が出る可能性があるとしている。5
  • 同一ユーザー権限の別プロセスは、同じユーザーコンテキストで復号できる前提で考えるべきである。これは文書上のスコープ定義からの推論である。6

DPAPIが向くケース

  • 典型的なWin32/.NETデスクトップアプリ
  • APIキー以外も含めて少量の秘密設定をまとめて保護したい場合
  • 保存先はアプリ側で管理したいが、鍵管理はOSに任せたい場合

4. Credential Manager

Credential Managerの方式

Win32のCredWrite / CredReadで、Windowsのユーザー資格情報セットに資格情報を書き込む。APIキー用途では通常CRED_TYPE_GENERICを使う。789

Credential Managerに関するMicrosoft文書上のポイント

  • CredWriteは、現在のトークンのログオンセッションに紐づくユーザーの資格情報セットに新規作成または更新を行う。7
  • CredReadは、その資格情報セットから資格情報を読み出す。8
  • CREDENTIAL構造体では、CRED_TYPE_GENERICCredentialBlobはアプリケーション定義である。9
  • CredentialBlobSizeの上限は5*512バイトであり、通常のAPIキー文字列なら十分収まる。9
  • 永続化スコープとしてCRED_PERSIST_SESSIONCRED_PERSIST_LOCAL_MACHINECRED_PERSIST_ENTERPRISEを選べる。9

Credential Managerの実装上の意味

Credential Managerは、DPAPIのように「暗号化してどこかに保存する」のではなく、OSが管理する資格情報ストアに1レコードとして保存する方式である。

APIキー用途では、例えば以下のように扱う。

  • TargetName: サービス名や環境名
  • Type: CRED_TYPE_GENERIC
  • CredentialBlob: APIキー本体
  • Persist: セッション限定、ローカル永続、エンタープライズ永続

Credential Managerの利点

  • Win32デスクトップアプリから直接使える
  • ファイル形式や暗号化済みBLOBの管理が不要
  • APIキー1件を「名前付き資格情報」として扱う用途に向く
  • 永続化スコープをAPIで明示できる

Credential Managerの制約

  • データモデルは資格情報レコード前提であり、複数設定をまとめて保存する用途には向きにくい
  • 読み出し時には平文がプロセスに返る
  • CredReadのアクセス単位は現在のトークンのログオンセッションであるため、同一ユーザー権限プロセスへの耐性は限定的と考えるべきである。これはMicrosoft文書のアクセス境界からの推論である。8
  • CRED_PERSIST_ENTERPRISEは構成によって他コンピューターのログオンセッションにも見えるため、ローミング要件を確認すべきである。9

Credential Managerが向くケース

  • Win32/.NETクライアントで、APIキーを1件または少数の資格情報として保存したい場合
  • アプリ独自の暗号化ファイルを持ちたくない場合
  • Windowsネイティブの資格情報ストアに寄せたい場合

5. Credential Locker(PasswordVault

Credential Lockerの方式

WinRTのWindows.Security.Credentials.PasswordVaultを使って、Credential Lockerに資格情報を保存する。310

Credential Lockerに関するMicrosoft文書上のポイント

  • MicrosoftはCredential Lockerを、資格情報を安全に保存・取得し、Microsoftアカウントでデバイス間ローミングさせる仕組みとして説明している。3
  • このAPIは元々UWP向けだが、WinUIアプリやパッケージ化デスクトップアプリでも使えるとしている。3
  • Microsoftはベストプラクティスとして、Credential Lockerはパスワード用途にのみ使い、大きなデータBLOBには使わないよう案内している。3
  • Microsoftは同じ記事で、平文で保存しないことを明記している。3
  • PasswordVault文書では、ロッカーはユーザー単位であり、AppContainer内アプリは自分のロッカーだけにアクセスできる一方、通常のデスクトップアプリはそのユーザーのすべてのロッカーにアクセスできるとしている。10

Credential Lockerの実装上の意味

Credential Lockerは、Windowsの現代アプリモデル寄りの資格情報ストアである。
保存単位もresourceuserNamepasswordという形で、パスワード型の資格情報に寄っている。

そのため、APIキーが単なる短い文字列であれば保存自体は可能だが、次の点を意識する必要がある。

  • Win32/WinForms/WPFの一般的なEXEでは、DPAPIやCredential Managerより自然とは言いにくい
  • ローミングが要件に合うか確認が必要
  • AppContainer外のデスクトップアプリでは、アプリ単位の強い分離を前提にしにくい

Credential Lockerの利点

  • WinRTアプリモデルに沿った資格情報保存API
  • 保存・取得・削除のAPIが単純
  • パスワード型の資格情報保存には適合する

Credential Lockerの制約

  • APIキー保存の第一候補というより、サインイン資格情報保存の延長として理解するほうが自然
  • AppContainer外デスクトップアプリではアクセス境界が広い
  • Microsoft文書上も大きなデータBLOB用途は想定していない

Credential Lockerが向くケース

  • UWP / WinUI / パッケージ化デスクトップアプリ
  • すでにPasswordVaultを使う設計がある場合
  • APIキーというより、ユーザーの保存済み資格情報に近いデータを扱う場合

比較表

方式保存実体Windows API / モデル配布物解析への強さファイル持ち出しへの強さ同一ユーザー権限への強さWindowsデスクトップアプリでの適合性
コード埋め込みEXE/DLL/リソース特になし実装は容易だが、機密保持方式としては不適
平文ファイルjson/ini/DB/レジストリ特になし実装は容易だが、本番の機密APIキーには不適
DPAPIアプリ管理の暗号化BLOBCryptProtectData / .NET ProtectedData高。典型的なWin32/.NETクライアント向け
Credential ManagerOS管理の資格情報レコードCredWrite / CredRead高。APIキー1件を資格情報として保存しやすい
Credential LockerOS管理のWinRT資格情報ロッカーPasswordVault中。UWP/WinUI/パッケージ化アプリ寄り

選び方

一般的なWin32 / .NET実行ファイル

候補はDPAPIまたはCredential Managerでよい。

  • APIキー以外の秘密設定もまとめて保護したい
    → DPAPI
  • APIキーを「1件の資格情報」としてOSストアに保存したい
    → Credential Manager

LocalMachineを使うか

クライアントPCでは、原則として避けるほうがよい。
MicrosoftはLocalMachineについて、そのコンピューター上の任意のプロセスまたは任意のユーザーが復号できると説明している。46

Credential Lockerを選ぶ場面

次の条件を満たす場合に限定して検討すればよい。

  • すでにWinRT / UWP / WinUI / packaged desktopの文脈にある
  • 保存対象がパスワード型の小さな文字列である
  • ローミングやアクセス境界の仕様を理解している

選ばない方式

  • コード埋め込み: 配布後に秘密として扱えない
  • 平文ファイル: 機密情報のローカル保存方式として弱い

まとめ

Windows実行ファイルで機密APIキーを保持する前提なら、比較対象の中で現実的なのはDPAPI、Credential Manager、状況限定でCredential Lockerである。

  • コード埋め込みは、配布型ネイティブアプリの共有秘密として扱うべきではない
  • 平文ファイルは、機密情報の保存方式として弱い
  • DPAPIは、任意データをアプリ側保存先に暗号化して置く方式
  • Credential Managerは、OSの資格情報ストアに名前付き資格情報として保存する方式
  • Credential Lockerは、WinRTアプリモデル寄りのパスワード保存方式

Windowsデスクトップアプリでの第一候補は、通常 DPAPI(CurrentUser) か Credential Manager(CRED_TYPE_GENERIC) である。

参考資料

Footnotes

  1. IETF, RFC 8252: OAuth 2.0 for Native Apps(2017)。ネイティブアプリに静的に含まれる共有シークレットを機密として扱うべきでないことを記述。https://datatracker.ietf.org/doc/html/rfc8252 2

  2. NIST, SP 800-57 Part 2 Rev. 1: Recommendation for Key Management - Part 2: Best Practices for Key Management Organizations。鍵情報保存時の機密性・完全性保護、アクセス制御要件を記述。https://doi.org/10.6028/NIST.SP.800-57pt2r1 2

  3. Microsoft Learn, Credential locker for Windows apps。Credential Lockerの用途、WinUI/packaged desktopでの利用、ベストプラクティスを記述。https://learn.microsoft.com/en-us/windows/apps/develop/security/credential-locker 2 3 4 5 6 7 8

  4. Microsoft Learn, CryptProtectData function (dpapi.h) - Win32 apps。DPAPIのユーザー/マシンスコープ、MAC付与、CRYPTPROTECT_LOCAL_MACHINEの挙動を記述。https://learn.microsoft.com/en-us/windows/win32/api/dpapi/nf-dpapi-cryptprotectdata 2 3 4 5 6 7

  5. Microsoft Learn, ProtectedData Class (System.Security.Cryptography)。.NETからDPAPIを利用するためのラッパーと、ユーザープロファイル依存などの注意点を記述。https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.protecteddata?view=windowsdesktop-10.0 2 3 4

  6. Microsoft Learn, DataProtectionScope Enum (System.Security.Cryptography)CurrentUserLocalMachineの差異、およびLocalMachine利用時の注意を記述。https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.dataprotectionscope?view=windowsdesktop-9.0 2 3 4 5

  7. Microsoft Learn, CredWriteW function (wincred.h) - Win32 apps。現在トークンのログオンセッションに紐づくユーザー資格情報セットへの書き込みを記述。https://learn.microsoft.com/en-us/windows/win32/api/wincred/nf-wincred-credwritew 2 3

  8. Microsoft Learn, CredReadW function (wincred.h) - Win32 apps。現在トークンのログオンセッションに紐づくユーザー資格情報セットからの読み出しを記述。https://learn.microsoft.com/en-us/windows/win32/api/wincred/nf-wincred-credreadw 2 3 4 5

  9. Microsoft Learn, CREDENTIALW structure (wincred.h) - Win32 appsCRED_TYPE_GENERICCredentialBlob、永続化種別、サイズ上限を記述。https://learn.microsoft.com/en-us/windows/win32/api/wincred/ns-wincred-credentialw 2 3 4 5 6

  10. Microsoft Learn, PasswordVault Class (Windows.Security.Credentials)。ユーザー単位のロッカーであること、およびAppContainer外デスクトップアプリのアクセス境界を記述。https://learn.microsoft.com/en-us/uwp/api/windows.security.credentials.passwordvault?view=winrt-26100 2 3 4