Брелок iOS не отримує значення з фону


85

Наразі я зберігаю ім’я користувача (електронну адресу) та солений хеш електронної пошти та пароля в iOS KeyChain. Я використовую ARC'ified версію, знайдену тут .

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 або пристроєм.

Користувач відключає місцезнаходження (моніторинг регіону), і я хочу оновити сервер із їх статусом. Я намагаюся витягнути маркер із брелока, так само, як і для кожного іншого дзвінка в мережу, і оновлюю статус. Але для деяких користувачів значення дорівнює нулю. Без цього я не можу оновити мережеві дані. Чому це працює для більшості, але не для невеликого відсотка?

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

Я повернувся до версії брелочного обгортки, яка не є ARC, але все одно отримую ті самі результати. Буду вдячний за будь-який відгук щодо цього. Це лише невелика частина моїх користувачів, але це питання, яке я хотів би виправити і не хвилюватися. Заздалегідь спасибі.

Крім того, вся моя фонова робота налаштована у backgroundTask, щоб запобігти тимчасовому завершенню речей. У мене не виникає жодних проблем з роботою навколо брелока, але я не дозволяю рухатися далі, поки мій маркер не буде заповнений.

EDIT Я розібрався у своїй проблемі з тим, що брелок не отримує значення з фону. Я розміщу відповідь нижче і прийму її, оскільки, на мою думку, це питання може стати цінним для інших пізніше.

Відповіді:


110

Моє запитання було близьким до позначки з тієї причини, але не зовсім. Прочитавши блог за блогом, підручник за підручником, я нарешті знайшов такий, який давав натяк на те, що може відбуватися.

Заблоковані домашні екрани. Підручники з брелоків завжди залишали порожніми налаштування доступності для брелока, тому за замовчуванням це буде найнижчий / найбезпечніший рівень доступу Apple. Однак цей рівень не дозволяє отримати доступ до брелока, якщо користувач має пароль на екрані блокування. Бінго! Це пояснює епізодичну поведінку і те, чому це трапляється лише у невеликого відсотка користувачів.

Один рядок коду вирішує всю безлад.

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

Додайте цей рядок, де я встановлюю значення імені користувача та пароля. Працює як шарм. Сподіваюся, це допоможе комусь там. Це мене бентежило досить довго, поки я не зміг скласти шматки.


1
Дякую! Це було дуже корисно.
Rich Waters

3
Ми буквально мали справу з цим тижнями. Ти рятівник життя!
OC Rickard,

15
Будь ласка, уникайте, …AccessibleAlwaysякщо це можливо, або зберігайте маркер, який надає лише обмежені привілеї (наприклад, маркер, який дозволяє читати нові елементи стрічки, але не публікувати). Цим ви явно відмовляєтесь від рівня шифрування. Якщо ваш додаток може зачекати до першого розблокування, можливо, було б найкраще скористатися …AfterFirstUnlockта скерувати користувачів спочатку розблокувати свої пристрої.
millenomi

14
Це насправді погана ідея, оскільки це означає, що ці дані облікових даних більше не захищаються. Хоча трохи більше роботи, важливо створити похідні облікові дані, ніж просто використовувати для обмеженого доступу, який, як ви очікуєте, буде потрібно у фоновому режимі і не більше. Цей обмежений термін дії облікових даних може закінчитися через деякий проміжок часу, і новий створюється кожного разу, коли додаток відкривається, а недійсні старі. Це забезпечує безпеку користувача на випадок, якщо похідні облікові дані порушено. Зверніться до сесії 204 WWDC 2013, щоб почути про це.
Joey Hagedorn

7
лунає @JoeyHagedorn тут - слухайте сесію 204 WWDC 2013 «Що нового з багатозадачністю» на позначці 44:24 та сесію WWDC 2013 709 «Захист секретів брелоком» о 25:30. Ви можете побачити текстовий зміст цих переговорів на сайті asciiwwdc.com
Шазрон,

63

Використовуйте kSecAttrAccessibleAfterFirstUnlockзамість kSecAttrAccessibleAlways.


З документації Apple :

kSecAttrAccessibleAfterFirstUnlock
Дані в елементі брелока не можуть отримати доступ після перезапуску, поки користувач не розблокує пристрій один раз.

Після першого розблокування дані залишаються доступними до наступного перезапуску. Це рекомендується для елементів, до яких потрібно отримати доступ у фонових програмах. Елементи з цим атрибутом переносяться на новий пристрій під час використання зашифрованих резервних копій.


4
Ця відповідь має бути коментарем ...
Frizlab

Ця відповідь здається ідеальною, оскільки kSecAttrAccessibleAlwaysвона вже застаріла
Sazzad Hissain Khan

1

У моєму випадку watchOS2 отримує доступ до даних брелоків на стороні iOS.

На початку використовується kSecAttrAccessibleWhenUnlockedThisDeviceOnly. Я можу читати дані незалежно від того, заблоковано iPhone чи ні. Мене дуже бентежить, що я отримаю помилку, коли годинник намагається отримати доступ до брелока:: SecTrustEvaluate [лист IssuerCommonName SubjectCommonName]

І в деяких випадках це стане:: SecOSStatusWith помилка: [- 25308] Помилка домену = NSOSStatusErrorDomain Код = -25308 "ks_crypt: e00002e2 не вдалося" oe "елемент (клас 6, пакет: 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]);
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.