Keychain — 主要概念、アーキテクチャと動作の仕組み

著者: IT Sectr 公開日: 2026-03-14 読了時間: 10 分

Keychain は、iOS、watchOS、macOS、tvOSにおける安全な認証情報ストレージで、パスワード、キー、証明書をハードウェアレベルで管理します。UserDefaultsとは異なり、Keychainのデータは暗号化され、アプリケーションのサンドボックスごとに隔離されます。Apple Developer Documentationによると、KeychainはSecure EnclaveメカニズムとAES-256ハードウェア暗号化を使用して機密情報を保護します。

重要ポイント

  • Keychain — ハードウェア暗号化によるパスワード、キー、証明書のためのiOSシステムストレージ
  • Security framework はKeychainを操作するためのC関数SecItemAdd、SecItemCopyMatching、SecItemDeleteを提供
  • Keychainへのアクセス はアプリのサンドボックスに制限されるが、keychain access groupsによる共有アクセスが可能
  • 属性kSecAttrAccessible が保護レベルを定義:AlwaysからWhenUnlockedThisDeviceOnlyまで
  • Keychain はパスワード、対称鍵・非対称鍵、X.509証明書の保存をサポート

Keychainとは?

Keychain は、パスワード、暗号鍵、証明書、その他の機密データを安全に保存するために設計されたAppleオペレーティングシステムの安全なデータベースです。Keychainは1999年にMac OS 8.6で初めて登場し、iOSでは最初のSDKバージョンから利用可能です。

定義と目的

Keychainはモバイル開発の基本的な問題を解決します:安全でないファイルシステムでの秘密情報(トークン、パスワード、暗号鍵)の保存です。UserDefaultsやSQLiteとは異なり、Keychainのデータは暗号化された状態で保存され、ディスクに書き込まれる際に自動的に暗号化されます。

各iOSアプリケーションは独立したサンドボックスで動作し、自分のkeychainにのみアクセスできます。ただし、開発者はkeychain access groupsを通じて、同じ開発者のアプリケーション間でKeychainへの共有アクセスを設定できます。ユーザーのiCloud Keychainは、エンドツーエンド暗号化を通じてデバイス間でデータを同期します。

Apple Security White Paper(2025年)によると、Keychainはデバイスの一意識別子(UID)に紐づく鍵でAES-256ハードウェア暗号化を使用し、デバイスから抽出してもデータにアクセスできないようにします。

iOSでのKeychainの動作

Keychainは階層型サービスとして機能します:アプリケーションがSecurity frameworkにアクセスし、Security frameworkが暗号化されたSQLite Keychainデータベースを管理するsecuritydデーモンと通信します。各レコードは個別の鍵で暗号化され、鍵自体はA7チップ以降のデバイスでSecure Enclaveハードウェアモジュールによって保護されます。

Security frameworkのアーキテクチャ

Security frameworkはKeychain Servicesを操作するためのCインターフェースを提供します。主な関数:SecItemAdd(追加)、SecItemCopyMatching(検索)、SecItemUpdate(更新)、SecItemDelete(削除)。各操作はリクエストタイプを記述するCFDictionaryRef属性辞書を受け取ります。

データはクラスによって分類されます:kSecClassGenericPassword(任意のパスワード)、kSecClassInternetPassword(インターネットサービスのパスワード)、kSecClassCertificate(証明書)、kSecClassKey(暗号鍵)、kSecClassIdentity(鍵と証明書のペア)。

データ保存プロセス

パスワードを保存する際、アプリケーションは属性を含む辞書を作成します:サービス、アカウント、アクセスレベル、ラベル。Security framework はデータをsecuritydデーモンに渡し、デーモンがデバイスに紐づく鍵でレコードを暗号化してKeychain SQLiteに保存します。取得も同様に機能します:属性によるクエリ、検索、復号化、データの返却。

重要な特徴:アプリケーションが削除されると、iOSは自動的にそのアプリケーションが作成したKeychainレコードを消去します(iOS 10.3+以降)。アプリケーションを再インストールしても、iCloud Keychainを使用していない限り、以前のインストールのKeychainデータは利用できません。

swift
import Security

func savePassword(service: String, account: String, password: Data) {
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrService as String: service,
        kSecAttrAccount as String: account,
        kSecValueData as String: password,
        kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
    ]
    SecItemAdd(query as CFDictionary, nil)
}

Keychainのデータタイプ

Keychainは5つの主要なデータクラスをサポートし、それぞれに独自の属性セットと適用範囲があります。クラスの選択により、利用可能な検索キーとデータの暗号化方法が決まります。

パスワードとアカウント

kSecClassGenericPassword クラスと kSecClassInternetPassword クラスは、文字列パスワードを保存するために設計されています。インターネット版はさらにサーバーデータ(ドメイン、プロトコル、ポート、認証パス)を保存します。GenericPasswordはサーバーに依存しない任意のパスワードの保存に使用されます。

インターネットパスワードを保存する際は、kSecAttrServer(ドメイン)、kSecAttrProtocol(HTTPS、FTPなど)、kSecAttrPortkSecAttrPath を指定できます。これにより、AutoFillによる自動入力時にレコードを正確に識別できます。

暗号鍵と証明書

kSecClassKey クラスは対称鍵(AES)と非対称鍵(RSA、EC)を保存します。kSecClassCertificate クラスはX.509証明書を保存します。kSecClassIdentity クラスは秘密鍵と対応する証明書を1つのレコードに結合します。

非対称鍵の場合、Keychainは属性をサポートします:kSecAttrKeyType(RSA、EC)、kSecAttrKeySizeInBits(2048、256)、kSecAttrIsPermanent(Keychainに保存するかどうか)。証明書の場合:kSecAttrLabel(人間が読める名前)、kSecAttrSubject(所有者のDN)、kSecAttrIssuer(発行者のDN)。

Keychainクラス目的データ型
kSecClassGenericPasswordアプリのパスワードData(NSString)
kSecClassInternetPasswordサーバーパスワードData + サーバー属性
kSecClassCertificateX.509証明書SecCertificate
kSecClassKey暗号鍵SecKey
kSecClassIdentity鍵 + 証明書SecIdentity

APIを介したKeychainの操作

ネイティブiOSコードでKeychainを操作するための主要なインターフェースは、Security frameworkの関数です。SwiftとObjective-Cでは、便利な関数にラップされた単一のCインターフェースが利用可能です。

基本操作 SecItemAdd と SecItemCopyMatching

SecItemAdd 関数は新しいアイテムをKeychainに追加します。クラス、データ、属性を含む辞書を入力として受け取り、ステータスerrSecSuccess(0)またはエラーコードを返します。SecItemCopyMatching 関数は属性による検索を実行し、見つかったデータを返します。

検索にはkSecReturnData フラグを使用します — trueの場合、関数はレコードの内容を返します。kSecMatchLimit フラグは結果の数を指定します:kSecMatchLimitOne(1つ)またはkSecMatchLimitAll(すべて)。

swift
func readPassword(service: String, account: String) -> Data? {
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrService as String: service,
        kSecAttrAccount as String: account,
        kSecReturnData as String: true,
        kSecMatchLimit as String: kSecMatchLimitOne
    ]
    var item: CFTypeRef?
    let status = SecItemCopyMatching(query as CFDictionary, &item)
    guard status == errSecSuccess else { return nil }
    return item as? Data
}

レコードの削除と更新

SecItemUpdate は既存のレコードの属性やデータを変更できます。SecItemDelete は渡された辞書に一致するすべてのレコードを削除します。削除時には、共有keychain内の他のレコードを誤って削除しないよう、十分な属性を指定することが重要です。

swift
func deletePassword(service: String, account: String) {
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrService as String: service,
        kSecAttrAccount as String: account
    ]
    SecItemDelete(query as CFDictionary)
}

アクセスレベルとデータ保護

各KeychainレコードにはkSecAttrAccessible 属性があり、データがいつ読み取り可能かを決定します。これはセキュリティ上非常に重要です:誤ったアクセスレベルはデータを脆弱にしたり、逆に必要なときに利用できなくしたりする可能性があります。

可用性定数

kSecAttrAccessibleWhenUnlocked — データはデバイスのロックが解除されている場合のみ利用可能。kSecAttrAccessibleAfterFirstUnlock — 再起動後の最初のロック解除後に利用可能。kSecAttrAccessibleAlways — 常に利用可能(推奨されません)。ThisDeviceOnly 接尾辞はバックアップによるデータ転送を防ぎます。

Secure Enclave 搭載デバイスでは、Keychainの暗号鍵を生体認証でさらに保護できます:kSecAccessControlBiometryCurrentSet または kSecAccessControlUserPresence。これにより、各読み取り操作にFace IDまたはTouch IDが必要になります。

iCloud Keychainと同期

iCloud Keychain はエンドツーエンド暗号化を通じてAppleデバイス間でレコードを同期します。Appleは復号化されたデータにアクセスできません。同期を有効にするには、kSecAttrSynchronizable 属性を値kCFBooleanTrueで追加します。

重要:同期されたレコードにはThisDeviceOnly 属性を含めることはできません。他のデバイスで利用可能である必要があるからです。すべてのデバイスを失った場合、iCloud KeychainはリカバリコードまたはiCloudリカバリキーを使用して復元できます。

アクセスレベル選択のベストプラクティス

認証トークンには、kSecAttrAccessibleWhenUnlockedThisDeviceOnlyを使用します — データはデバイスのロック解除時にのみ利用可能で、バックアップにコピーされません。バックグラウンドタスクで利用可能にする必要がある証明書には、kSecAttrAccessibleAfterFirstUnlockを使用します。機密データにkSecAttrAccessibleAlwaysを使用しないでください。

同期を必要としないデータには、常にThisDeviceOnly 接尾辞を追加することをお勧めします。これにより、iCloudやiTunesバックアップへの秘密情報の誤ったコピーを防ぎます。重要なデータについては、アクセシビリティとkSecAccessControlUserPresenceを組み合わせてください — これにより、レコードの復号化に生体認証またはパスコードが必要になります。

iCloud Keychain を使用する場合、同期されたレコードはすべてのユーザーデバイスで利用可能であることに注意してください:攻撃者が1つのデバイスにアクセスすると、すべてのデバイスのデータが危険にさらされる可能性があります。分離された秘密情報にはThisDeviceOnlyを使用してください。

よくある質問

KeychainはUserDefaultsとどう違うのですか?

UserDefaults はデータをプレーンテキストで.plistファイルに保存し、IPA解析中にアクセス可能です。Keychainは各レコードを個別に暗号化し、ハードウェア暗号化を使用し、アクセスレベル、生体認証、iCloud経由の同期をサポートします。

テスト中にKeychainをクリアするには?

iOSシミュレータを起動するたびに、Keychainはクリアされます。実機では、アプリを削除すると、iOSがそのデベロッパーのすべてのKeychainレコードを削除します。選択的にクリアするには、適切な属性を指定してSecItemDeleteを呼び出します。

2つのアプリケーションでKeychainを共有できますか?

はい、keychain access groups を通じて可能です。アプリケーションはプロビジョニングプロファイルに同じteam IDを持ち、同じkeychain-access-groupsを持つentitlementsが必要です。デベロッパーはXcode Capabilitiesで共有アクセスを設定します。

Keychainのデータサイズの上限は?

Appleは厳格な制限を文書化していませんが、実際には1レコードあたり1〜4KBを超えないことが推奨されています。より大きな容量の場合は、ファイル暗号化を使用し、鍵をKeychainに保存し、データ自体はDocumentsに保存します。

ジェイルブレイクデバイスではKeychainは安全ですか?

ジェイルブレイク デバイスでは、攻撃者がルートアクセスを取得し、Keychain SQLiteを直接読み取ることができるため、Keychainの保護は低下します。重要なデータには、サーバーから取得した鍵による追加の暗号化を使用してください。

まとめ

  • Keychain — AES-256ハードウェア暗号化によるパスワード、キー、証明書のためのiOS安全ストレージ
  • Security framework はC-APIを提供:書き込み用SecItemAdd、読み取り用SecItemCopyMatching、削除用SecItemDelete
  • Keychainデータクラス:GenericPassword、InternetPassword、Certificate、Key、Identity — それぞれ独自の属性セットを持つ
  • kSecAttrAccessible がアクセスレベルを制御:WhenUnlocked、AfterFirstUnlock、Always、ThisDeviceOnlyオプション
  • iCloud Keychain はkSecAttrSynchronizable属性でエンドツーエンド暗号化を通じてデバイス間でレコードを同期
  • 生体認証(Face ID / Touch ID)はkSecAccessControlBiometryCurrentSetを通じてKeychainアクセスを保護
  • OAuthトークン、パスワード、暗号鍵の保存にはKeychainを使用 — UserDefaultsに秘密情報を保存しないでください

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください