axiom-file-protection-ref について
iOS 開発者向けに、ファイル保護 API の選択と適用方法をまとめたリファレンスです。保護レベル、アクセス可能なタイミング、バックグラウンド動作、Keychain との違いを説明します。
主な機能
- 014 種類のファイル保護レベルの比較
- 02新規・既存ファイルへの保護設定
- 03ファイルの保護レベルの確認
- 04バックグラウンドアクセス動作の評価
- 05ファイル保護と Keychain の比較
- 06保護ファイルのアクセス問題の調査
活用シーン
- 01機密文書の保護レベル選定
- 02デバイスロック中のファイルアクセス失敗への対処
- 03ファイルを読むバックグラウンドタスクの対応
- 04秘密情報と大容量データの保存先選び
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ charleswiltgen/ axiom --skill axiom-file-protection-refインストール後、Claude Code で/axiom-file-protection-refを入力して読み込まれたか確認します。
詳細
iOS ファイル保護リファレンス
目的:ファイル暗号化およびデータ保護 API の包括的なリファレンス
利用可能時期:iOS 4.0 以降(すべての保護レベル)、最新の機能強化は iOS 26
コンテキスト:ハードウェア暗号化を使用する iOS データ保護アーキテクチャを基盤としています
このスキルを使う場面
次のような場合に、このスキルを使用してください。
- 保存データ内の機密性の高いユーザーデータを保護する
- ファイルに適切な FileProtectionType を選択する
- ファイルがいつアクセス可能または暗号化されるかを理解する
- デバイスのロック後に「ファイルにアクセスできない」というエラーをデバッグする
- 安全なファイルストレージを実装する
- Keychain とファイル保護のアプローチを比較する
- バックグラウンドでのファイルアクセス要件に対応する
概要
iOS データ保護は、デバイスのパスコードに紐付いたハードウェアアクセラレーションによるファイル暗号化を提供します。ユーザーがパスコードを設定すると、すべてのファイルを、そのパスコードで保護された鍵を使って暗号化できます。
主な概念:
- 保護が有効な場合、ファイルは自動的に暗号化されます
- 暗号化キーはデバイスのハードウェアとユーザーのパスコードから導出されます
- 保護レベルに応じて、デバイスがロックされるとファイルにアクセスできなくなります
- パフォーマンスへの影響はありません(ハードウェア AES 暗号化)
保護レベルの比較
| レベル | 暗号化が解除されるまで | アクセス可能な条件 | 用途 | バックグラウンドアクセス |
|---|---|---|---|---|
| complete | デバイスのロック解除まで | ロック解除中のみ | 機密データ(健康情報、金融情報) | ❌ いいえ |
| completeUnlessOpen | ファイルが閉じられるまで | 最初のロック解除後、ファイルが開いている間 | 大容量ダウンロード、動画 | ✅ すでに開いている場合 |
| completeUntilFirstUserAuthentication | 起動後、最初にロック解除するまで | 最初のロック解除後 | ほとんどのアプリデータ | ✅ はい |
| none | 暗号化されません | 常に | 公開キャッシュ、一時ファイル | ✅ はい |
各レベルの詳細
.complete
詳細な説明:
「ファイルはディスク上で暗号化された形式で保存され、デバイスがロック中または起動中は読み取りも書き込みもできません。」
用途:
- ユーザーの健康データ
- 金融情報
- パスワード保管庫
- 機密文書
- 個人の写真(アプリで最大限のセキュリティが必要な場合)
動作:
- 暗号化:✅ 常時
- アクセス可能な条件:デバイスのロック解除中のみ
- バックグラウンドアクセス:❌ いいえ(ロック中はアプリから読み取れません)
- 起動後に利用可能:❌ いいえ(ユーザーがロック解除するまで)
コード例:
// ✅ CORRECT: Maximum security for sensitive data
func saveSensitiveData(_ data: Data, to url: URL) throws {
try data.write(to: url, options: .completeFileProtection)
}
// Or set on existing file
try FileManager.default.setAttributes(
[.protectionKey: FileProtectionType.complete],
ofItemAtPath: url.path
)
トレードオフ:
- ✅ 最大限のセキュリティ
- ❌ バックグラウンドではアクセスできません
- ❌ ロック中にアプリがアクセスしようとすると、ユーザーにエラーが表示されます
.completeUnlessOpen
詳細な説明:
「ファイルは閉じられた後、ディスク上で暗号化された形式で保存されます。」
用途:
- 大容量ファイルのダウンロード(バックグラウンドで継続)
- 再生中の動画ファイル
- 編集中のドキュメント
- 開いている間にバックグラウンドアクセスが必要なファイル
動作:
- 暗号化:✅ 閉じているとき
- アクセス可能な条件:最初のロック解除後、開いている間はアクセス可能な状態を維持
- バックグラウンドアクセス:✅ はい(すでにファイルが開いていた場合)
- 起動後に利用可能:❌ いいえ(最初にロック解除するまで)
コード例:
// ✅ CORRECT: Download in background, but encrypted when closed
func startBackgroundDownload(url: URL, destination: URL) throws {
try Data().write(to: destination, options: .completeFileProtectionUnlessOpen)
// Open file handle for writing
let fileHandle = try FileHandle(forWritingTo: destination)
// Download continues in background
// File remains accessible because it's open
// When closed, file becomes encrypted
// Later, when download complete:
try fileHandle.close() // Now encrypted until next unlock
}
トレードオフ:
- ✅ 適切なセキュリティ(使用していないときは暗号化)
- ✅ バックグラウンドアクセス(すでに開いている場合)
- ⚠️ 開いている間は脆弱です
.completeUntilFirstUserAuthentication
詳細な説明:
「ファイルはディスク上で暗号化された形式で保存され、デバイスの起動後までアクセスできません。」
用途:
- ほとんどのアプリケーションデータ
- ユーザー設定
- ダウンロードしたコンテンツ
- データベースファイル
- バックグラウンドアクセスが必要なものすべて
動作:
- 暗号化:✅ 常時
- アクセス可能な条件:起動後、最初にロック解除した後
- バックグラウンドアクセス:✅ はい(最初のロック解除後)
- 起動後に利用可能:❌ いいえ(ユーザーが一度ロック解除するまで)
ほとんどのファイルでは、これをデフォルトとして推奨します。
コード例:
// ✅ CORRECT: Balanced security for most app data
func saveAppData(_ data: Data, to url: URL) throws {
try data.write(
to: url,
options: .completeFileProtectionUntilFirstUserAuthentication
)
}
// ✅ This file can be accessed in background after first unlock
func backgroundTaskCanAccessFile() {
// This works even if device is locked (after first unlock)
let data = try? Data(contentsOf: url)
}
トレードオフ:
- ✅ 起動中に保護されます(電源オフ中にデバイスが盗まれた場合)
- ✅ バックグラウンドアクセス(通常の動作)
- ⚠️ ロック中もアクセス可能です(.complete より保護が弱くなります)
.none
詳細な説明:
「このファイルには、特別な保護が設定されていません。」
用途:
- 公開キャッシュデータ
- 一時ファイル
- 機密性のないダウンロードファイル
- サムネイル
- やむを得ない場合に限る
動作:
- 暗号化:❌ されません
- アクセス可能:✅ 常に可能
- バックグラウンドでのアクセス:✅ 常に可能
- 起動後の利用可能性:✅ 常に利用可能
コード例:
// ⚠️ USE SPARINGLY: Only for truly non-sensitive data
func cachePublicThumbnail(_ data: Data, to url: URL) throws {
try data.write(to: url, options: .noFileProtection)
}
トレードオフ:
- ✅ 常にアクセス可能
- ❌ 暗号化されません
- ❌ デバイスが盗まれた場合に脆弱です
ファイル保護の設定
ファイル作成時
// ✅ RECOMMENDED: Set protection when writing
let sensitiveData = userData.jsonData()
try sensitiveData.write(
to: fileURL,
options: .completeFileProtection
)
既存のファイルの場合
// ✅ CORRECT: Change protection on existing file
try FileManager.default.setAttributes(
[.protectionKey: FileProtectionType.complete],
ofItemAtPath: fileURL.path
)
ディレクトリのデフォルトの保護
// ✅ CORRECT: Set default protection for directory
// New files inherit this protection
try FileManager.default.setAttributes(
[.protectionKey: FileProtectionType.completeUntilFirstUserAuthentication],
ofItemAtPath: directoryURL.path
)
現在の保護レベルの確認
// ✅ Check file's current protection level
func checkFileProtection(at url: URL) throws -> FileProtectionType? {
let attributes = try FileManager.default.attributesOfItem(atPath: url.path)
return attributes[.protectionKey] as? FileProtectionType
}
// Usage
if let protection = try? checkFileProtection(at: fileURL) {
switch protection {
case .complete:
print("Maximum protection")
case .completeUntilFirstUserAuthentication:
print("Standard protection")
default:
print("Other protection")
}
}
ファイル保護と Keychain の比較
選択マトリックス
| 用途 | 推奨 | 理由 |
|---|---|---|
| パスワード、トークン、キー | Keychain | 小さなシークレット向けに設計されています |
| 小さな機密値(数 KB 未満) | Keychain | より安全で、個別に暗号化されます |
| 1 KB を超えるファイル | ファイル保護 | Keychain は大きなデータ向けに設計されていません |
| ユーザードキュメント | ファイル保護 | ファイルベースのストレージとして自然です |
| 構造化されたシークレット | Keychain | キーによる検索とアクセス制御が可能です |
コードの比較
// ✅ CORRECT: Small secrets in Keychain
let passwordData = password.data(using: .utf8)!
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "userPassword",
kSecValueData as String: passwordData,
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
]
SecItemAdd(query as CFDictionary, nil)
// ✅ CORRECT: Files with file protection
let userData = try JSONEncoder().encode(user)
try userData.write(to: fileURL, options: .completeFileProtection)
Keychain の利点:
- より細かなアクセス制御(Face ID/Touch ID)
- 独立した暗号化(ファイルシステムに依存しません)
- (設定によっては)アプリを削除しても保持されます
ファイル保護の利点:
- 既存のファイル操作で利用できます
- 大きなデータを効率的に扱えます
- 最小限のコードで自動的に適用されます
バックグラウンドアクセスに関する考慮事項
iOS のバックグラウンドモードとファイル保護
// ❌ WRONG: .complete files can't be accessed in background
class BackgroundTask {
func performBackgroundSync() {
// This FAILS if file has .complete protection and device is locked
let data = try? Data(contentsOf: sensitiveFileURL)
// data will be nil if device locked
}
}
// ✅ CORRECT: Use .completeUntilFirstUserAuthentication
// Files accessible in background after first unlock
try data.write(
to: fileURL,
options: .completeFileProtectionUntilFirstUserAuthentication
)
保護に関するエラーへの対処
// ✅ CORRECT: Handle protection errors gracefully
func readFile(at url: URL) -> Data? {
do {
return try Data(contentsOf: url)
} catch let error as NSError {
if error.domain == NSCocoaErrorDomain &&
error.code == NSFileReadNoPermissionError {
// File is protected and device is locked
print("File protected, device locked")
return nil
}
throw error
}
}
iCloud とファイル保護
iCloud での保護の仕組み
ローカルファイルの保護:
- ローカルのキャッシュコピーに適用されます
- iCloud に保存されたバージョンには影響しません
- iCloud には独自の暗号化機能があります(転送中および保存時)
iCloud の暗号化:
- すべての iCloud データは保存時に暗号化されます(Apple 管理のキー)
- 一部のデータタイプではエンドツーエンド暗号化を利用できます(Advanced Data Protection)
- ファイル保護が影響するのはローカルデバイスのみです
// ✅ CORRECT: Protection on iCloud file affects local copy only
func saveToICloud(data: Data, filename: String) throws {
guard let iCloudURL = FileManager.default.url(
forUbiquityContainerIdentifier: nil
) else { return }
let fileURL = iCloudURL.appendingPathComponent(filename)
// This protection applies to local cached copy
try data.write(to: fileURL, options: .completeFileProtection)
// iCloud has separate encryption for cloud storage
}
よくあるパターン
パターン 1:新しいアプリのデフォルトの保護
// ✅ RECOMMENDED: Set default protection at app launch
func configureDefaultFileProtection() {
let fileManager = FileManager.default
let directories: [FileManager.SearchPathDirectory] = [
.documentDirectory,
.applicationSupportDirectory
]
for directory in directories {
guard let url = fileManager.urls(
for: directory,
in: .userDomainMask
).first else { continue }
try? fileManager.setAttributes(
[.protectionKey: FileProtectionType.completeUntilFirstUserAuthentication],
ofItemAtPath: url.path
)
}
}
// Call during app initialization
func application(_ application: UIApplication, didFinishLaunchingWithOptions...) {
configureDefaultFileProtection()
return true
}
パターン 2:データベースファイルの暗号化
// ✅ CORRECT: Protect SwiftData/SQLite database
let appSupportURL = FileManager.default.urls(
for: .applicationSupportDirectory,
in: .userDomainMask
)[0]
let databaseURL = appSupportURL.appendingPathComponent("app.sqlite")
// Set protection before creating database
try? FileManager.default.setAttributes(
[.protectionKey: FileProtectionType.completeUntilFirstUserAuthentication],
ofItemAtPath: appSupportURL.path
)
// Now create database - it inherits protection
let container = try ModelContainer(
for: MyModel.self,
configurations: ModelConfiguration(url: databaseURL)
)
パターン 3:バックグラウンドタスク用に保護レベルを下げる
// ⚠️ SOMETIMES NECESSARY: Lower protection for background access
func enableBackgroundAccess(for url: URL) throws {
try FileManager.default.setAttributes(
[.protectionKey: FileProtectionType.completeUntilFirstUserAuthentication],
ofItemAtPath: url.path
)
}
// Only do this if:
// 1. Background access is truly required
// 2. Data sensitivity allows it
// 3. You've considered security tradeoffs
ファイル保護の問題のデバッグ
問題:バックグラウンドでファイルにアクセスできない
症状:バックグラウンドタスクでファイルの読み取りに失敗します
// Debug: Check current protection
if let protection = try? FileManager.default.attributesOfItem(
atPath: url.path
)[.protectionKey] as? FileProtectionType {
print("Protection: \(protection)")
if protection == .complete {
print("❌ Can't access in background when locked")
}
}
解決策:代わりに .completeUntilFirstUserAuthentication を使用します
問題:再起動後にファイルへアクセスできない
症状:デバイスの再起動直後にアプリがファイルへアクセスできません
原因:.complete または .completeUntilFirstUserAuthentication を使用しています(仕様どおりの動作です)
解決策:想定される動作です。次のいずれかを行います:
- ユーザーがデバイスのロックを解除するまで待ちます
- 適切な UI で問題に対処します
- アクセス可能である必要があるファイルには
.noneを使用します(セキュリティとのトレードオフ)
Entitlements
ファイル保護は通常、特別なエンタイトルメントなしで機能しますが、一部の機能には次の設定が必要です:
Data Protection Entitlement
<key>com.apple.developer.default-data-protection</key>
<string>NSFileProtectionComplete</string>
必要となる場合:
.complete保護を使用する場合- 一部の iOS バージョンで、あらゆる保護を使用する場合(ドキュメントを確認してください)
追加方法:
- Xcode → Target → Signing & Capabilities
- 「+ Capability」→ Data Protection
- 保護レベルを選択します
クイックリファレンステーブル
| シナリオ | 推奨される保護 | ロック中にアクセス可能か | バックグラウンドでアクセス可能か |
|---|---|---|---|
| ユーザーの健康データ | .complete | ❌ いいえ | ❌ いいえ |
| 財務記録 | .complete | ❌ いいえ | ❌ いいえ |
| ほとんどのアプリデータ | .completeUntilFirstUserAuthentication | ✅ はい(初回ロック解除後) | ✅ はい |
| ダウンロード(大容量ファイル) | .completeUnlessOpen | ✅ 開いている間 | ✅ 開いている間 |
| データベースファイル | .completeUntilFirstUserAuthentication | ✅ はい | ✅ はい |
| ダウンロードした画像 | .completeUntilFirstUserAuthentication | ✅ はい | ✅ はい |
| 公開キャッシュ | .none | ✅ はい | ✅ はい |
| 一時ファイル | .none | ✅ はい | ✅ はい |
関連スキル
axiom-storage— ファイル保護とその他のセキュリティ対策のどちらを使うか判断しますaxiom-storage-management-ref— ファイルのライフサイクル、削除、ディスク管理axiom-storage-diag— ファイルアクセスの問題をデバッグしますaxiom-keychain— 認証情報(トークン、パスワード、キー)を安全に保存しますaxiom-keychain-ref— SecItem API の完全なリファレンスaxiom-cryptokit— CryptoKit による暗号化と署名
最終更新日: 2025-12-12 スキルの種類: リファレンス 最小 iOS バージョン: 4.0(すべての保護レベル) 最新の更新: iOS 26