6

iosのキーチェーン(keychainItemWrapper/SSKeychain)を使用してアプリケーションのログイントークンを保存し、ログイン状態を維持しています。現在、私は自分のトークン、トークンの有効期限、リフレッシュトークンを含むキーチェーンに単純なNSDictionaryを格納しています。私はそれをNSDataにシリアル化し、kSecValueDataを使って格納します。 kSecAttrAccountkSecAttrServiceも設定しますが、認証用には使用しないでください。KeyChainにログイントークンを格納しているiosがまれにランダムに取得できませんでしたが、一貫して

これは、約95%の時間がかかります。問題は、ランダムに、予期せず、散発的に、私がトークンを取得するように要求したときにキーチェーンがデータを返さないということです。それは通常、アプリケーションを中断した後、再オープンするときです。それは、バックグラウンドからでなくても、特定の遅延の後である必要はありません。

NSDataの質問に特に失敗し、<ABCD EFGH IJKL ....>の代わりに<>が返されます。私はそれがゼロだと思う。したがって、コードは、ログアウトエラー、トークンの期限切れエラーなどなく、ユーザーがログインしていないと思ってすぐにアプリケーションのサインアップ/ログインのランディングページにドロップします。もし私がアプリを最小限に抑えてから再び開くと、ほとんど常に正しいキーチェーンinfoと入力し、再度ログインします。

これは、遭遇したときに混乱を招くことがあります。また、ユーザーはこの真の100%のログイン状態を維持できず、時折ランダムにログアウトされることもあります。私はそれを予測したりデバッグしたり、キーチェーンライブラリを変更することができず、以下のように私のためにそれを修正していません。私といくつかのTestFlightユーザー、そして現在私たちのプロダクションアプリで起こっています。

キーチェーンの整合性を維持し、100%の時間をロードする方法を教えてください。このような場合に使用するトークンにNSUserDefaultsバックアップストレージを実装する準備が整いました。実際には認証トークンを保存する必要はありません。

保管:

// load keychain 
KeychainItemWrapper *keychainItem = [KeychainItemWrapper keyChainWrapperForKeyID:kcIdentifier]; 
NSString *firstLaunch = [keychainItem objectForKey: (__bridge id)(kSecAttrAccount)]; 
if (firstLaunch == nil){ 
    // initialize if needed 
    [keychainItem setObject:email forKey: (__bridge id)(kSecAttrAccount)]; 
    [keychainItem setObject:kcIdentifier forKey: (__bridge id)kSecAttrService]; 
    [keychainItem setObject:(id)kSecAttrAccessibleAfterFirstUnlock forKey:(id)kSecAttrAccessible]; 
} 

// serialize "auth" NSDictionary into NSData and store 
NSString *error; 
NSData *dictionaryData = [NSPropertyListSerialization dataFromPropertyList:auth format:NSPropertyListXMLFormat_v1_0 errorDescription:&error]; 
[keychainItem setObject:dictionaryData forKey:(id)kSecValueData]; 

ロード:私も広く利用可能であるSSKeychainライブラリCocoaPod、およびキーチェーンロジックのラッパーを使用してみましたが

// after similar KeychainItemWrapper initialization as above 
NSData *dictionaryData = [keychainItem objectForKey:(id)kSecValueData]; 
NSString *error; 

NSDictionary *auth = [NSPropertyListSerialization propertyListFromData:dictionaryData mutabilityOption:NSPropertyListImmutable format:nil errorDescription:&error]; 
NSString *token = auth[@"access_token"]; 

。よりクリーンなアクセスですが、同じ問題で失敗します。ここにはの値を格納しているだけなので、libにNSDataを格納する直接の方法がないためです。

// store in keychain 
[SSKeychain setAccessibilityType:kSecAttrAccessibleAfterFirstUnlock]; 
[SSKeychain setPassword:auth[@"access_token"] forService:SSKEYCHAIN_SERVICE account:SSKEYCHAIN_TOKEN]; 
[SSKeychain setPassword:auth[@"expires_at"] forService:SSKEYCHAIN_SERVICE account:SSKEYCHAIN_EXPIRES_AT]; 
[SSKeychain setPassword:auth[@"refresh_token"] forService:SSKEYCHAIN_SERVICE account:SSKEYCHAIN_REFRESH_TOKEN]; 

// load from keychain 
[SSKeychain setAccessibilityType:kSecAttrAccessibleAfterFirstUnlock]; 
NSString *token = [SSKeychain passwordForService:SSKEYCHAIN_SERVICE account:SSKEYCHAIN_TOKEN]; 
NSString *expires_at = [SSKeychain passwordForService:SSKEYCHAIN_SERVICE account:SSKEYCHAIN_EXPIRES_AT]; 
NSString *refresh_token = [SSKeychain passwordForService:SSKEYCHAIN_SERVICE account:SSKEYCHAIN_REFRESH_TOKEN]; 
+0

キーチェーンに問題が発生した場合は、エラーコードが表示されます。それは何ですか? – Segev

+0

私は同じ問題を抱えています。ここでは、検索はランダムに失敗します。ヘルパーメソッド - 文字列へのキーチェーンエラーコード:https://gist.github.com/inorganik/f9971e65f71e037650b39b5f182e157e – inorganik

+0

エラーを記録しようとします。私が使用しているライブラリの中で、&errorparamを公開していない可能性があります。 – Miro

答えて

3

キーチェーンには現在のところ問題があります。それはあなたが軽く元気に降りているように聞こえます。通常、アプリケーションの強制終了は、それを元に戻すために必要です。

1つのことは、最初のリクエストでキーチェーンに一度だけアクセスしてからメモリに結果をキャッシュすることです。すでにメモリに保存されている場合は、そこから返されます。

これが発生したときに特定のエラーが発生した場合は、それをトラップして再試行するか、不幸なアプリケーションの場合のように再試行してください。あなたがそれらの問題を議論するためのハイテクチケットを発行すれば、実際にはAppleの現在の指針となる。

唯一の他の本当の解決策は、データを暗号化してファイルに保存することですが、暗号化キーに問題があります。これは鋭い攻撃者に対する難読化よりも少し難しいです。

+0

は、一般的に複数のスレッドにわたってキーチェーンでスレッドセーフであるか、アクセスポイントを同期させることについて心配すべきですか?私はすでにSSKeychainによって、おそらくそれがすでに処理されていることを読むことを覚えているようです。 – Miro

+0

それ自体がスレッドセーフで、SSKeychainはより多くのデータ型と効率ラッパーです – Wain

関連する問題