2016-05-16 15 views
6

Tôi đang sử dụng khóa ios (keychainItemWrapper/SSKeychain) để lưu mã thông báo đăng nhập của ứng dụng và duy trì trạng thái đăng nhập. Hiện tại tôi lưu trữ một đơn giản NSDictionary trong keychain chứa mã thông báo của tôi, hết hạn mã thông báo và mã thông báo làm mới. Tôi sắp xếp nó vào NSData và lưu trữ bằng cách sử dụng kSecValueData. Tôi cũng đặt kSecAttrAccountkSecAttrService, nhưng không sử dụng những thông tin đó cho auth.ios lưu trữ mã thông báo đăng nhập trong KeyChain không thể truy xuất, hiếm khi và ngẫu nhiên, nhưng nhất quán

Công trình này tuyệt vời, khoảng 95% thời gian. Vấn đề là rằng ngẫu nhiên, không thể đoán trước và rời rạc, keychain không trả lại dữ liệu khi tôi yêu cầu nó để lấy mã thông báo. Nó thường là sau một thời gian vừa phải ra khỏi ứng dụng, khi mở lại nó. Nó không phải là từ nền, hoặc sau bất kỳ sự chậm trễ cụ thể mặc dù.

Không thành công khi yêu cầu NSData dưới đây và trả lại <> thay vì <ABCD EFGH IJKL ....>. Tôi nghĩ là không. Do đó, mã cho rằng người dùng không đăng nhập và bỏ chúng ngay lập tức trên trang đích Đăng nhập/Đăng nhập của ứng dụng của tôi, mà không có lỗi đăng xuất, lỗi hết hạn mã thông báo, v.v. Nếu tôi thu nhỏ ứng dụng, sau đó mở lại, nó hầu như luôn nhận được đúng khóa thông tin và người dùng đã đăng nhập lại.

Điều này tạo ra một trải nghiệm khó hiểu khi gặp phải. Điều này cũng có nghĩa là người dùng không thể duy trì trạng thái đăng nhập 100% thực sự này, đôi khi bị đăng xuất ngẫu nhiên. Tôi đã không thể dự đoán nó hoặc gỡ lỗi nó và thay đổi thư viện keychain, như hình dưới đây, đã không cố định nó cho tôi. Nó xảy ra với tôi, và một số người dùng TestFlight, và trong ứng dụng sản xuất của chúng tôi hiện nay.

Bất kỳ đề xuất nào về cách duy trì tính toàn vẹn của keychain và tải 100% thời gian? Chúng ta đã sẵn sàng để thực hiện một lưu trữ sao lưu NSUserDefaults trên mã thông báo để sử dụng trong những trường hợp này, một cái gì đó tôi thực sự không muốn làm để lưu trữ một mã thông báo auth.

Lưu trữ:

// 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]; 

Chở Hàng:

// 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"]; 

Tôi cũng đã cố gắng sử dụng các thư viện SSKeychain CocoaPod đó là phổ biến rộng rãi, và một bọc xung quanh logic keychain. Nó là một truy cập sạch hơn nhưng không thành công với cùng một vấn đề. Ở đây tôi chỉ lưu trữ các giá trị NSString vì không có cách nào trực tiếp để lưu trữ NSData trong lib.

// 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

Nếu khóa không thành công, bạn sẽ nhận được mã lỗi. Nó là gì? – Segev

+0

Tôi có cùng một vấn đề, nơi truy xuất ngẫu nhiên không thành công. Dưới đây là phương thức trợ giúp - mã lỗi keychain cho chuỗi: https://gist.github.com/inorganik/f9971e65f71e037650b39b5f182e157e – inorganik

+0

tôi sẽ cố gắng ghi lại lỗi. nó có khả năng xảy ra bên trong các thư viện tôi sử dụng, mà không phơi bày một tham số & lỗi. – Miro

Trả lời

3

Keychain hiện có vấn đề tại thời điểm này và thực sự khá lâu. Nghe có vẻ như bạn đang nhận được tắt nhẹ như thường khi nó phá vỡ một lực lượng bỏ thuốc lá của ứng dụng được yêu cầu để đưa nó trở lại cuộc sống.

Một điều giúp ích là truy cập vào keychain chỉ một lần vào yêu cầu đầu tiên và sau đó lưu vào bộ nhớ cache kết quả trong bộ nhớ, nếu nó đã có trong bộ nhớ thì chỉ cần trả lại từ đó.

Nếu bạn có thể quan sát một lỗi cụ thể khi điều này xảy ra, hãy bẫy và thử lại hoặc, như trường hợp hiện tại đối với một số ứng dụng không may, hãy xóa ứng dụng. Giết ứng dụng thực sự là hướng dẫn hiện tại của Apple nếu bạn tăng vé công nghệ để thảo luận vấn đề với họ.

Giải pháp thực sự duy nhất khác là mã hóa dữ liệu và lưu trữ nó trong một tệp, nhưng sau đó bạn có vấn đề với các khóa mã hóa, vì vậy điều này tốt hơn một chút so với việc gây khó chịu đối với kẻ tấn công quan tâm.

+0

là keychain thường là chủ đề an toàn trên nhiều chủ đề, hoặc tôi nên lo lắng về @ đồng bộ hóa các điểm truy cập? Tôi dường như nhớ đọc nó đã được xử lý rồi, có lẽ bởi SSKeychain ít nhất. – Miro

+0

Nó là chính nó thread an toàn, SSKeychain là nhiều hơn một kiểu dữ liệu và hiệu quả wrapper – Wain

Các vấn đề liên quan