Il KeyChain iOS non recupera i valori dallo sfondo


87

Attualmente sto memorizzando il nome utente (e-mail) e un hash salato dell'e-mail e della password nel KeyChain iOS. Sto usando la versione ARC'ified trovata qui .

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

Tutto funziona bene quando devo estrarre il token per le mie chiamate di rete mentre l'app è attiva. Funziona per l'accesso da un avvio pulito, così come per tutte le chiamate di rete. Il problema inizia quando l'app è in background.

Tieni presente che questo accade solo sporadicamente e devo ancora fissarlo a una versione o dispositivo iOS specifico.

L'utente fa scattare una posizione (monitoraggio della regione) e voglio aggiornare il server con il loro stato. Cerco di estrarre il token dal portachiavi, come faccio per ogni altra chiamata di rete e aggiorno lo stato. Ma per alcuni utenti, il valore è nullo. Senza di esso, non posso aggiornare le cose di rete. Perché dovrebbe funzionare per la maggior parte, ma non per una piccola percentuale?

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

Sono tornato alla versione non ARC del keychainwrapper, ma ottengo comunque gli stessi risultati. Apprezzerei qualsiasi feedback su questo. È solo una piccola parte dei miei utenti, ma è un problema che vorrei risolvere e di cui non mi preoccupo. Grazie in anticipo.

Inoltre, tutto il mio lavoro in background è impostato in un backgroundTask per evitare che le cose scadano. Non ho problemi con il lavoro che circonda il portachiavi, ma non lascio che le cose vadano avanti finché il mio token non è pieno.

MODIFICA Ho capito il mio problema con il portachiavi che non recupera i valori dallo sfondo. Pubblicherò la risposta di seguito e l'accetterò poiché ritengo che questa domanda possa diventare preziosa per altri in seguito.

Risposte:


110

La mia domanda era vicina al segno per il motivo, ma non del tutto. Dopo aver letto blog dopo blog, tutorial dopo tutorial, finalmente ne ho trovato uno che dava un indizio di ciò che potrebbe accadere.

Schermate iniziali bloccate. I tutorial sul portachiavi lasciano sempre vuote le impostazioni di accessibilità per il portachiavi, quindi verrà impostato il livello di accesso più basso / più sicuro di Apple. Questo livello, tuttavia, non consente l'accesso al portachiavi se l'utente dispone di un passcode nella schermata di blocco. Bingo! Questo spiega il comportamento sporadico e perché ciò accade solo a una piccola percentuale di utenti.

Una riga di codice, risolve l'intero pasticcio.

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

Aggiungi questa riga in cui sto impostando i valori di nome utente e password. Funziona come un fascino. Spero che questo possa aiutare qualcuno là fuori. Mi ha confuso per un po 'finché non sono stato in grado di mettere insieme i pezzi.


1
Grazie! Questo è stato molto utile.
Rich Waters

3
Ci siamo letteralmente occupati di questo da settimane. Sei un salvavita!
OC Rickard

15
Evita …AccessibleAlwaysse possibile o archivia un token che fornisce solo privilegi limitati (ad esempio un token che ti consente di leggere nuovi elementi del feed ma non di pubblicare). In questo modo, rinunci esplicitamente a un livello di crittografia. Se la tua app può aspettare fino al primo sblocco, forse sarebbe meglio usare …AfterFirstUnlocke indirizzare gli utenti a sbloccare prima i loro dispositivi.
millenomi

14
Questa è davvero una cattiva idea perché significa che questi dati delle credenziali non sono più protetti. Mentre un po 'più di lavoro, è importante creare una credenziale derivativa che può essere utilizzata solo per l'accesso limitato che ti aspetti essere richiesto in background e non di più. Quelle credenziali limitate possono scadere dopo un certo periodo di tempo e ne viene creata una nuova ogni volta che viene aperta l'app, invalidando quelle vecchie. Ciò mantiene l'utente al sicuro nel caso in cui le credenziali derivate siano compromesse. Fare riferimento alla sessione 204 del WWDC 2013 per saperne di più.
Joey Hagedorn

7
echeggiando qui @JoeyHagedorn - ascolta la sessione 204 della WWDC 2013 "Novità del multitasking" al numero 44:24 e la sessione 709 della WWDC 2013 "Proteggere i segreti con il portachiavi" al numero delle 25:30. Puoi vedere il contenuto testuale di questi colloqui su asciiwwdc.com
Shazron

64

Usa kSecAttrAccessibleAfterFirstUnlockinvece di kSecAttrAccessibleAlways.


Dalla documentazione di Apple :

kSecAttrAccessibleAfterFirstUnlock
Non è possibile accedere ai dati nell'elemento portachiavi dopo un riavvio fino a quando il dispositivo non è stato sbloccato una volta dall'utente.

Dopo il primo sblocco, i dati rimangono accessibili fino al successivo riavvio. Consigliato per elementi a cui è necessario accedere da applicazioni in background. Gli elementi con questo attributo vengono migrati su un nuovo dispositivo quando si utilizzano backup crittografati.


4
Questa risposta dovrebbe essere un commento ...
Frizlab

Questa risposta sembra perfetta perché kSecAttrAccessibleAlwaysè già deprecata
Sazzad Hissain Khan

1

Nel mio caso, watchOS2 accede ai dati del portachiavi sul lato iOS.

All'inizio viene utilizzato kSecAttrAccessibleWhenUnlockedThisDeviceOnly. Posso leggere i dati indipendentemente dal fatto che l'iPhone sia bloccato o meno. Mi confonde molto il fatto che ricevo un messaggio di errore quando l'orologio tenta di accedere al portachiavi:: SecTrustEvaluate [leaf IssuerCommonName SubjectCommonName]

E in alcuni casi diventerà:: SecOSStatusWith errore: [- 25308] Error Domain = NSOSStatusErrorDomain Code = -25308 "ks_crypt: e00002e2 non è riuscito a 'oe' l'elemento (classe 6, bag: 0) Accesso all'elemento tentato mentre il portachiavi è bloccato. " UserInfo = {NSDescription = ks_crypt: e00002e2 non è riuscito a 'oe' l'oggetto (classe 6, bag: 0) Tentativo di accesso all'oggetto mentre il portachiavi è bloccato.}

Aggiornerò la mia risposta se avrò più informazioni.


0

Ciò potrebbe accadere a causa della politica di protezione dei dati di Apple che è oscura dal punto di vista degli sviluppatori. La soluzione alternativa è quando l'app viene avviata controlla se il portachiavi è accessibile o meno, se non accessibile potresti uccidere la tua app (con un popup appropriato) a seconda dei tipi di app.

+(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]);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.