iOSKeyChainがバックグラウンドから値を取得しない


85

現在、iOS KeyChainにユーザー名(メール)とメールとパスワードのソルトハッシュを保存しています。ここにあるARC化バージョンを使用しています

KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyCustomIdentifier" accessGroup:nil];
[wrapper setObject:APP_NAME forKey:(__bridge id)kSecAttrService];
[wrapper setObject:email forKey:(__bridge id)kSecAttrAccount];
[wrapper setObject:token forKey:(__bridge id)kSecValueData];

アプリがアクティブなときにネットワーク呼び出しのためにトークンを引き出す必要がある場合、これはすべて正常に機能します。クリーンなスタートアップからのログインだけでなく、すべてのネットワーク呼び出しで機能します。アプリがバックグラウンドにあるときに問題が発生します。

これは散発的にのみ発生し、特定のiOSバージョンまたはデバイスにまだピン留めしていないことに注意してください。

ユーザーが場所をトリップし(リージョンモニタリング)、サーバーをステータスで更新したいと思います。他のすべてのネットワーク呼び出しの場合と同じように、キーチェーンからトークンを引き出して、ステータスを更新しようとします。ただし、一部のユーザーの場合、値はnilです。それがないと、ネットワーク関連のものを更新できません。なぜこれはほとんどの場合に機能しますが、一部では機能しないのでしょうか。

KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyCustomIdentifier" accessGroup:nil];
NSString *token = [wrapper objectForKey:(__bridge id)kSecValueData];

キーチェーンラッパーの非ARCバージョンに戻りましたが、それでも同じ結果が得られます。これについてのフィードバックをいただければ幸いです。これは私のユーザーのごく一部ですが、修正したい問題であり、心配する必要はありません。前もって感謝します。

また、私のバックグラウンド作業はすべて、タイムアウトを防ぐためにbackgroundTaskで設定されています。キーチェーンを取り巻く作業に問題はありませんが、トークンがいっぱいになるまで問題は発生しません。

編集 私は彼らのキーチェーンがバックグラウンドから値を取得しないという私の問題を理解しました。この質問は後で他の人にとって価値があると思うので、以下に回答を投稿して受け入れます。

回答:


110

私の質問は、その理由のためにマークに近かったが、完全ではなかった。ブログを次々と、チュートリアルを次々と読んだ後、私はついに何が起こっているのかについてのヒントを発するものを見つけました。

ロックされたホーム画面。キーチェーンのチュートリアルでは、キーチェーンのユーザー補助設定が常に空白のままになっているため、デフォルトでAppleの最低/最も安全なアクセスレベルになります。ただし、このレベルでは、ユーザーがロック画面にパスコードを持っている場合、キーチェーンアクセスは許可されません。ビンゴ!これは、散発的な動作と、これがごく一部のユーザーにしか発生しない理由を説明しています。

1行のコードで、混乱全体を解決します。

[wrapper setObject:(__bridge id)kSecAttrAccessibleAlways forKey:(__bridge id)kSecAttrAccessible];

ユーザー名とパスワードの値を設定する場所にこの行を追加します。チャームのように機能します。これが誰かを助けることを願っています。ピースを組み立てることができるようになるまで、それは私をかなり長い間混​​乱させました。


1
ありがとう!これはとても役に立ちました。
リッチウォーターズ

3
私たちは文字通り何週間もこれに取り組んできました。あなたは命の恩人です!
OC Rickard 2013年

15
…AccessibleAlways可能な限り避けるか、制限された特権のみを提供するトークン(たとえば、新しいフィードアイテムを読み取ることはできるが、投稿することはできないトークン)を保存してください。そうすることで、暗号化のレベルを明示的に放棄します。アプリが最初のロック解除まで待つことができる場合は、最初に…AfterFirstUnlockデバイスのロックを解除するようにユーザーに指示するのがおそらく最善でしょう。
ミレノミ2013年

14
これは、この資格情報データが保護されなくなったことを意味するため、非常に悪い考えです。もう少し作業が必要ですが、バックグラウンドで必要とされると予想される制限付きアクセスに使用できるものよりも派生的な資格情報を作成することが重要です。その制限された認証情報は、一定期間後に期限切れになる可能性があり、アプリを開くたびに新しい認証情報が作成され、古い認証情報が無効になります。これにより、派生資格情報が危険にさらされた場合にユーザーを安全に保つことができます。これについては、WWDC2013セッション204を参照してください。
Joey Hagedorn 2013年

7
ここに@JoeyHagedornをエコーし​​ます-44:24マークでWWDC2013セッション204「マルチタスクの新機能」を、25:30マークでWWDC2013セッション709「キーチェーンで秘密を保護する」を聞いてください。これらの講演のテキストコンテンツは、asciiwwdc.com
Shazron

63

kSecAttrAccessibleAfterFirstUnlock代わりに使用してくださいkSecAttrAccessibleAlways


Appleのドキュメントから:

kSecAttrAccessibleAfterFirstUnlock
キーチェーンアイテムのデータは、再起動後、ユーザーがデバイスのロックを解除するまでアクセスできません。

最初のロック解除後、次の再起動までデータにアクセスできます。これは、バックグラウンドアプリケーションからアクセスする必要があるアイテムに推奨されます。この属性を持つアイテムは、暗号化されたバックアップを使用するときに新しいデバイスに移行します。


4
この答えはコメントでなければなりません…
Frizlab 2014年

kSecAttrAccessibleAlwaysすでに廃止されているため、この回答は完璧に
思えます

1

私の場合、watchOS2はiOS側のキーチェーンデータにアクセスします。

最初は、kSecAttrAccessibleWhenUnlockedThisDeviceOnlyが使用されます。iPhoneがロックされていてもいなくてもデータを読み取ることができます。ウォッチがキーチェーンにアクセスしようとするとエラーが発生するのは非常に混乱しています:: SecTrustEvaluate [leaf IssuerCommonName SubjectCommonName]

場合によっては、次のようになります。:SecOSStatusWith error:[-25308] Error Domain = NSOSStatusErrorDomain Code = -25308 "ks_crypt:e00002e2 failed to'oe 'item(class 6、bag:0)キーチェーンがロックされているときにアイテムへのアクセスが試行されました。 「」UserInfo = {NSDescription = ks_crypt:e00002e2がアイテムの「oe」に失敗しました(クラス6、バッグ:0)キーチェーンがロックされているときにアイテムへのアクセスが試行されました。}

さらに情報が得られたら、回答を更新します。


0

これは、開発者の観点からはある程度あいまいなAppleのデータ保護ポリシーが原因で発生する可能性があります。回避策は、アプリの起動時にキーチェーンにアクセスできるかどうかを確認することです。アクセスできない場合は、アプリの種類によってはアプリを(適切なポップアップで)強制終了する可能性があります。

+(BOOL) isKeychainAccessible
{
    NSString *keychainTestKey = @"keychainTestKey";
    NSString *keychainTestValue = @"keychainTestValue";
    [self createKeychainValue:keychainTestValue forIdentifier:keychainTestKey];
    NSString *loadedValue = [self keychainStringFromMatchingIdentifier:keychainTestKey];
    [self deleteItemFromKeychainWithIdentifier:keychainTestKey];
    return ([keychainTestValue isEqualToString: loadedValue]);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.