本文へスキップ

iOS の Keychain と Android の Keystore、ユーザーセッションの保存場所を比較する

📋目次

はじめに

iOS シミュレータや Android のアプリデータを直接編集していると、ログイン状態やオンボーディングの完了フラグを保存しておいて、後から復元したくなる場面があります。

それを直接編集するために、実際にどのディレクトリに保存されているのか調べてみました。この記事はその備忘録です。

iOS Data Container

iOS アプリのファイルは、Data Container と呼ばれるサンドボックス内の領域に置かれます。plist や SQLite などアプリが作るファイルはすべてここに入ります。

iOS の Data Container の中身と、その外側にある Keychain の位置関係

シミュレータであれば、次のコマンドでアプリごとの Data Container のパスを取得できます。

xcrun simctl get_app_container <UDID> <bundle_id> data

このパスの中身には Library/Preferences の plist や Documents 配下のファイルが並びますが、Keychain のデータは含まれません。ちなみに、Keychain はアプリのサンドボックスの外にあります。Apple のセキュリティガイドによれば、実機では Keychain の鍵の一部が Secure Enclave によって保護され、秘密鍵の利用は必ず Secure Enclave を経由するとされています。

ログイン用トークンを Keychain に保存する設計を選んだ時点で、そのセッション情報は Data Container を対象にした操作の範囲外に置かれます。Data Container を直接編集して状態を作り込んでも、plist の表示設定は書き換えられる一方、Keychain のログイントークンには手が届きません。

Android 内部ストレージ

Android では事情が異なります。ユーザーセッションの保存先としてよく使われる SharedPreferences や Jetpack の DataStore Preferences は、アプリの内部ストレージ(/data/data/<package>/ 配下)に置かれるファイルです。iOS の Data Container に相当する領域の中に、そのまま存在します。

Android の内部ストレージの中身と、暗号化ファイルに鍵を提供する Keystore の位置関係

ただし機密情報をこの2つにそのまま保存するのは避け、Jetpack Security ライブラリが提供する EncryptedSharedPreferences を使い、Android Keystore が管理する鍵で暗号化する構成がよく使われます。Android Keystore のドキュメントには、次のように書かれています。

Use the Android Keystore provider to let an individual app store its own credentials, which only that app can access.

(Android Keystore provider を使うと、個々のアプリが自分専用の認証情報を保存でき、その情報には当該アプリだけがアクセスできる。)

Keystore の鍵はアプリごとに隔離されており、他のアプリから読み出せません。EncryptedSharedPreferences のファイル自体はアプリの内部ストレージの中にあるので、バックアップしたり復元したりはできますが、中身は Keystore の鍵で暗号化されているため、その鍵にアクセスできる状態でなければ復号できません。

まとめ

iOS の Keychain は Data Container の外にあり、Android の EncryptedSharedPreferences は内部ストレージの中で Keystore の鍵によって保護されています。同じ「セッション情報の保護」でも、隔離する場所が iOS と Android でまったく違いました。

Android 側の実装はわかってなかったので、良い機会になりました。次に忘れた頃には、自分でもこの記事を見返すと思います。よければ参考にしてみてください。

参考リンク

この記事をシェア