iOS KeyChain không truy xuất giá trị từ nền


85

Tôi hiện đang lưu trữ tên người dùng (email) và một hàm băm nhỏ của email và mật khẩu trong iOS KeyChain. Tôi đang sử dụng phiên bản ARC'ified được tìm thấy ở đây .

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

Tất cả điều này đều hoạt động tốt khi tôi cần rút mã thông báo cho các cuộc gọi mạng của mình trong khi ứng dụng đang hoạt động. Nó hoạt động để đăng nhập từ một khởi động sạch, cũng như tất cả các cuộc gọi mạng trong suốt. Rắc rối bắt đầu khi ứng dụng ở chế độ nền.

Hãy nhớ rằng điều này chỉ xảy ra thường xuyên và tôi vẫn chưa ghim nó vào một phiên bản hoặc thiết bị iOS cụ thể.

Người dùng đi đến một vị trí (giám sát khu vực) và tôi muốn cập nhật trạng thái của máy chủ. Tôi cố gắng rút mã thông báo ra khỏi chuỗi khóa, giống như cách tôi làm đối với mọi cuộc gọi mạng khác và cập nhật trạng thái. Nhưng đối với một số người dùng, giá trị là con số không. Không có nó, tôi không thể cập nhật nội dung mạng. Tại sao điều này sẽ hiệu quả với hầu hết, nhưng không phải với một tỷ lệ nhỏ?

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

Tôi đã quay lại phiên bản không phải ARC của keychainwrapper, nhưng tôi vẫn nhận được kết quả tương tự. Tôi sẽ đánh giá cao bất kỳ phản hồi nào về điều này. Đó chỉ là một phần nhỏ người dùng của tôi, nhưng đó là vấn đề tôi muốn khắc phục và không lo lắng. Cảm ơn trước.

Ngoài ra, tất cả công việc nền của tôi được thiết lập trong backgroundTask để ngăn mọi thứ quá thời gian. Tôi không gặp bất kỳ vấn đề nào với công việc xung quanh chuỗi khóa, nhưng tôi không để mọi thứ tiếp tục cho đến khi mã thông báo của tôi được lấp đầy.

CHỈNH SỬA Tôi đã tìm ra vấn đề của mình với việc họ không truy xuất các giá trị từ nền. Tôi sẽ đăng câu trả lời bên dưới và chấp nhận nó vì tôi cảm thấy câu hỏi này có thể trở nên có giá trị đối với những người khác sau này.

Câu trả lời:


110

Câu hỏi của tôi đã gần đến mức cho lý do tại sao, nhưng không hoàn toàn. Sau khi đọc hết blog này đến blog khác, hết hướng dẫn này đến hướng dẫn khác, cuối cùng tôi đã tìm thấy một thứ gợi ý về những gì có thể đang xảy ra.

Màn hình chính bị khóa. Các hướng dẫn về chuỗi khóa luôn để trống cài đặt trợ năng cho chuỗi khóa, vì vậy, nó sẽ được đặt mặc định ở mức truy cập thấp nhất / an toàn nhất của Apple. Tuy nhiên, cấp độ này không cho phép truy cập chuỗi khóa nếu người dùng có mật mã trên màn hình khóa. Chơi lô tô! Điều này giải thích hành vi rời rạc và tại sao điều này chỉ xảy ra với một tỷ lệ nhỏ người dùng.

Một dòng mã, giải quyết toàn bộ mớ hỗn độn.

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

Thêm dòng này nơi tôi đang đặt giá trị tên người dùng và mật khẩu. Hoạt động như một sự quyến rũ. Hy vọng điều này sẽ giúp ai đó ngoài kia. Nó khiến tôi bối rối một lúc khá lâu cho đến khi tôi có thể ghép các mảnh lại với nhau.


1
Cảm ơn! Điều này rất hữu ích.
Rich Waters,

3
Chúng tôi thực sự đã đối phó với điều này trong nhiều tuần. Bạn là một người tiết kiệm cuộc sống!
OC Rickard

15
Vui lòng tránh …AccessibleAlwaysnếu có thể, hoặc lưu trữ mã thông báo chỉ cung cấp các đặc quyền hạn chế (ví dụ: mã thông báo cho phép bạn đọc các mục nguồn cấp dữ liệu mới nhưng không đăng). Bạn đang loại bỏ một cấp độ mã hóa một cách rõ ràng bằng cách làm như vậy. Nếu ứng dụng của bạn có thể đợi cho đến lần mở khóa đầu tiên, có lẽ tốt nhất bạn nên sử dụng …AfterFirstUnlockvà hướng dẫn người dùng của mình mở khóa thiết bị của họ trước.
millenomi

14
Đây là một ý tưởng thực sự tồi vì nó có nghĩa là dữ liệu thông tin xác thực này không còn được bảo vệ. Trong khi nhiều công việc hơn một chút, điều quan trọng là tạo ra một thông tin xác thực phái sinh hơn là chỉ có thể được sử dụng cho quyền truy cập giới hạn mà bạn mong đợi được yêu cầu trong nền và không hơn thế nữa. Thông tin đăng nhập giới hạn đó có thể hết hạn sau một khoảng thời gian và một thông tin mới sẽ được tạo mỗi khi ứng dụng được mở, làm mất hiệu lực của các thông tin cũ. Điều này giúp người dùng an toàn trong trường hợp thông tin đăng nhập phái sinh bị xâm phạm. Tham khảo WWDC 2013 phiên 204 để nghe về điều này.
Joey Hagedorn

7
echoing @JoeyHagedorn tại đây - nghe WWDC 2013 Session 204 "Có gì mới với đa nhiệm" ở mốc 44:24 và WWDC 2013 Session 709 "Bảo vệ bí mật bằng Keychain" ở mốc 25:30. Bạn có thể xem nội dung văn bản của các cuộc đàm phán tại asciiwwdc.com
Shazron

63

Sử dụng kSecAttrAccessibleAfterFirstUnlockthay vì kSecAttrAccessibleAlways.


Từ tài liệu của Apple :

kSecAttrAccessibleAfterFirstUnlock
Không thể truy cập dữ liệu trong mục chuỗi khóa sau khi khởi động lại cho đến khi thiết bị được người dùng mở khóa một lần.

Sau lần mở khóa đầu tiên, dữ liệu vẫn có thể truy cập được cho đến lần khởi động lại tiếp theo. Điều này được khuyến nghị cho các mục cần được truy cập bằng ứng dụng nền. Các mục có thuộc tính này sẽ di chuyển sang thiết bị mới khi sử dụng bản sao lưu được mã hóa.


4
Câu trả lời này phải là một nhận xét ...
Frizlab

Câu trả lời này có vẻ hoàn hảo vì kSecAttrAccessibleAlwaysđã không được dùng nữa
Sazzad Hissain Khan

1

Trong trường hợp của tôi, watchOS2 truy cập vào dữ liệu chuỗi khóa ở phía iOS.

Lúc đầu, kSecAttrAccessibleWhenUnlockedThisDeviceOnly được sử dụng. Tôi có thể đọc dữ liệu cho dù iPhone có bị khóa hay không. Tôi rất khó hiểu rằng tôi sẽ nhận được Lỗi khi đồng hồ đang cố gắng truy cập chuỗi khóa:: SecTrustEvaluate [leaf IssuerCommonName SubjectCommonName]

Và một số trường hợp nó sẽ trở thành:: SecOSStatusVới lỗi: [- 25308] Error Domain = NSOSStatusErrorDomain Code = -25308 "ks_crypt: e00002e2 không thành công với mục 'oe' (lớp 6, túi: 0) Đã cố gắng truy cập vào mục trong khi chuỗi khóa bị khóa. " UserInfo = {NSDescription = ks_crypt: e00002e2 không thể 'oe' mục (lớp 6, túi: 0) Đã cố truy cập vào mục khi chuỗi khóa bị khóa.}

Tôi sẽ cập nhật câu trả lời của mình nếu tôi có thêm thông tin.


0

Điều này có thể xảy ra do chính sách bảo vệ dữ liệu của Táo khuyết ở một mức độ nào đó theo quan điểm của nhà phát triển. Cách giải quyết là khi ứng dụng khởi chạy kiểm tra xem chuỗi khóa có thể truy cập được hay không, nếu không truy cập được, bạn có thể giết ứng dụng của mình (với cửa sổ bật lên thích hợp) tùy thuộc vào loại ứng dụng của bạn.

+(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]);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.