Elimina gli elementi del portachiavi quando un'app viene disinstallata


238

Sto usando il codice scifihifi-iphone di idandersen per portachiavi e salvare la password usando

[SFHFKeychainUtils storeUsername:@"User" andPassword:@"123"
              forServiceName:@"TestService" updateExisting:YES error:&error];

Quando elimino l'applicazione dal dispositivo, la password rimane nel portachiavi.

Voglio rimuovere la password dal portachiavi quando l'utente elimina l'applicazione dal dispositivo. Come posso fare questo?


13
Poiché il tuo codice non viene eseguito quando l'applicazione viene eliminata, non hai modo di farlo.
Jonathan Grynspan,

1
Penso che puoi eliminare un elemento portachiavi solo dall'interno dell'app, ma non prima di disinstallarlo. Puoi dare un'occhiata al metodo deleteItem di SFHFKeychainUtils per eliminare un nome utente o una password dal portachiavi.
matteodv,

Risposte:


406

Puoi approfittare del fatto che NSUserDefaults vengono cancellati dalla disinstallazione di un'app. Per esempio:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //Clear keychain on first run in case of reinstallation
    if (![[NSUserDefaults standardUserDefaults] objectForKey:@"FirstRun"]) {
        // Delete values from keychain here
        [[NSUserDefaults standardUserDefaults] setValue:@"1strun" forKey:@"FirstRun"];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }

    //...Other stuff that usually happens in didFinishLaunching
}

Questo verifica e imposta una chiave / valore "FirstRun" NSUserDefaultsalla prima esecuzione dell'app se non è già impostata. C'è un commento in cui dovresti inserire il codice per eliminare i valori dal portachiavi. È possibile chiamare la sincronizzazione per assicurarsi che la chiave / valore "FirstRun" sia immediatamente persistente nel caso in cui l'utente uccida manualmente l'app prima che il sistema la persista.


2
Sono d'accordo con Amro che puoi eliminare / eliminare il tuo portachiavi al primo avvio dell'applicazione. Ciò eliminerà tutto ciò che è stato impostato prima della disinstallazione dell'app l'ultima volta. L'ho fatto per una delle mie app che memorizza le credenziali di Facebook / Twitter e ha funzionato abbastanza bene sapendo che solo la tua app ha accesso a qualsiasi portachiavi impostato.
XCool

Grazie per questo suggerimento.
iOSAppDev

3
NSUserDefaults non vengono cancellati quando l'utente esce manualmente dall'app. synchronizeIn questo caso, vengono persi solo i valori impostati ma il sistema (periodicamente) o non ancora sincronizzati con il disco (chiamando ). È una buona idea chiamare la sincronizzazione dopo aver impostato la prima chiave di esecuzione. E sì, NSUserDefaults viene cancellato quando un dispositivo viene ripristinato (e non ripristinato dal backup), e va bene in questo caso.
Amro,

5
Ti sbagli e probabilmente stai facendo qualcosa che causa l'eliminazione delle impostazioni predefinite dell'utente. L'intero punto di NSUserDefaults è salvare le preferenze e far sì che tali preferenze persistano attraverso il lancio multiplo di applicazioni. Ancora una volta, il ripristino del dispositivo o l'eliminazione di un'app rimuoveranno le impostazioni predefinite dell'utente. Guarda quante persone hanno votato a favore di questa risposta e controlla il tuo codice. Quindi vai a leggere la documentazione. Diamine, inviami il codice pertinente e ti mostrerò cosa stai facendo di sbagliato. È stato così da iOS 2.0. Giù il voto, ma suggerirei prima di scrivere un caso di test isolato, semplice.
Amro,

9
Non sarei molto fiducioso sull'uso di NSUserDefault per questo. Perché? Dai un'occhiata a quel thread: stackoverflow.com/questions/20269116/… . Se avvii la tua app dallo sfondo, ci sono casi in cui le tue chiavi personalizzate in NSUserDefaults non sono impostate. Applicare questa risposta porterebbe all'eliminazione delle chiavi personalizzate del tuo portachiavi, anche se non lo volevi davvero!
Aurelien Porte,

40

Per gli utenti che cercano una versione Swift 3.0 della risposta di @ amro:

let userDefaults = UserDefaults.standard

if !userDefaults.bool(forKey: "hasRunBefore") {
     // Remove Keychain items here

     // Update the flag indicator
     userDefaults.set(true, forKey: "hasRunBefore")
}

* nota che la funzione synchronize () è obsoleta


2
if !userDefaults.bool(forKey: "hasRunBefore") {È solo più pulito.
nefarianblack,

1
La chiamata di sincronizzazione deve essere rimossa.
Pochi,

30

Non è presente alcun trigger per eseguire il codice quando l'app viene eliminata dal dispositivo. L'accesso al portachiavi dipende dal profilo di provisioning utilizzato per firmare l'applicazione. Pertanto, nessun'altra applicazione sarebbe in grado di accedere a queste informazioni nel portachiavi.

Non aiuta con te lo scopo di rimuovere la password nel portachiavi quando l'utente elimina l'applicazione dal dispositivo, ma dovrebbe darti un certo conforto che la password non è accessibile (solo da una reinstallazione dell'applicazione originale).


Quindi, se cambiamo il profilo di provisioning della nostra applicazione, sarebbe in grado di accedere ai valori precedentemente memorizzati nel portachiavi.
Moaz Saeed,

27

Per chi cerca una versione Swift della risposta di @ amro:

    let userDefaults = NSUserDefaults.standardUserDefaults()

    if userDefaults.boolForKey("hasRunBefore") == false {

        // remove keychain items here


        // update the flag indicator
        userDefaults.setBool(true, forKey: "hasRunBefore")
        userDefaults.synchronize() // forces the app to update the NSUserDefaults

        return
    }

9

Versione Xamarin C #

    const string FIRST_RUN = "hasRunBefore";
    var userDefaults = NSUserDefaults.StandardUserDefaults;
    if (!userDefaults.BoolForKey(FIRST_RUN))
    {
        //TODO: remove keychain items
        userDefaults.SetBool(true, FIRST_RUN);
        userDefaults.Synchronize();
    }

... e per cancellare i record dal portachiavi (commento TODO sopra)

        var securityRecords = new[] { SecKind.GenericPassword,
                                    SecKind.Certificate,
                                    SecKind.Identity,
                                    SecKind.InternetPassword,
                                    SecKind.Key
                                };
        foreach (var recordKind in securityRecords)
        {
            SecRecord query = new SecRecord(recordKind);
            SecKeyChain.Remove(query);
        }

1
Utilizzando if (VersionTracking.IsFirstLaunchEver) {// remove keychain items}da Xamarin.Essentials non è necessario il codice per il file userDefaults. Xamarin.Essentials lo avvolge per te .
Christopher Stephan,

7

I file verranno eliminati dalla directory dei documenti dell'app quando l'utente disinstalla l'app. Sapendo questo, tutto ciò che devi fare è controllare se esiste un file come prima cosa che succede application:didFinishLaunchingWithOptions:. Successivamente, crea incondizionatamente il file (anche se è solo un file fittizio).

Se il file non esisteva al momento del controllo, sai che questa è la prima esecuzione dall'ultima installazione. Se hai bisogno di sapere più avanti nell'app, salva il risultato booleano nel membro delegato dell'app.


7

La risposta di @ amro tradotta in Swift 4.0:

if UserDefaults.standard.object(forKey: "FirstInstall") == nil {
    UserDefaults.standard.set(false, forKey: "FirstInstall")
    UserDefaults.standard.synchronize()
}

O anche if !UserDefaults.standard.bool(forKey: "FirstInstall")quale impostazione predefinita è false se la chiave non esiste. E .synchronize () non necessario.
Charles,

3

Questo sembra essere il comportamento predefinito su iOS 10.3 basato sul comportamento a cui le persone hanno assistito in beta # 2. Non ho ancora trovato alcuna documentazione ufficiale a riguardo, quindi commenta se hai.


7
Era fino alla beta 5, suppongo, la versione pubblica di iOS 10.3 non contiene questa modifica.
Jakub Truhlář
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.