Eliminar elementos de llavero cuando se desinstala una aplicación


238

Estoy usando el código scifihifi-iphone de idandersen para llavero y guardo la contraseña usando

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

Cuando elimino la aplicación del dispositivo, la contraseña permanece en el llavero.

Quiero eliminar la contraseña del llavero cuando el usuario elimina la aplicación del dispositivo. ¿Cómo puedo hacer esto?


13
Dado que su código no se ejecuta cuando se elimina su aplicación, no tiene forma de hacerlo.
Jonathan Grynspan el

1
Creo que puede eliminar un elemento de llavero solo desde el interior de la aplicación, pero no antes de desinstalarlo. Puede echar un vistazo al método deleteItem de SFHFKeychainUtils para eliminar un nombre de usuario o una contraseña del llavero.
matteodv

Respuestas:


406

Puede aprovechar el hecho de que NSUserDefaults se eliminan mediante la desinstalación de una aplicación. Por ejemplo:

- (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
}

Esto comprueba y establece una clave / valor "FirstRun" NSUserDefaultsen la primera ejecución de su aplicación si aún no está configurada. Hay un comentario en el que debe poner código para eliminar valores del llavero. Se puede llamar a Sincronizar para asegurarse de que la clave / valor "FirstRun" persista inmediatamente en caso de que el usuario mate la aplicación manualmente antes de que el sistema la persista.


2
Estoy de acuerdo con Amro en que puede eliminar / purgar su llavero en la primera ejecución de la aplicación. Esto eliminará todo lo que se configuró antes de que la aplicación se desinstalara la última vez. Hice esto para una de mis aplicaciones que almacena las credenciales de Facebook / Twitter y ha funcionado bastante bien sabiendo que solo su aplicación tiene acceso al llavero que se configuró.
XCool

Gracias por esta pista.
iOSAppDev

3
NSUserDefaults no se borran cuando el usuario cierra manualmente la aplicación. synchronizeEn ese caso, solo se pierden los valores que ha establecido, pero el sistema (periódicamente) o aún no se ha sincronizado con el disco (llamando ). Es una buena idea llamar a sincronizar después de configurar la primera tecla de ejecución. Y sí, NSUserDefaults se borran cuando un dispositivo se reinicia (y no se restaura desde la copia de seguridad), y eso está bien en este caso.
Amro

55
Estás equivocado y probablemente estás haciendo algo que hace que se borren los valores predeterminados del usuario. El objetivo principal de NSUserDefaults es guardar las preferencias y hacer que esas preferencias persistan a través de múltiples lanzamientos de aplicaciones. Nuevamente, restablecer el dispositivo o eliminar una aplicación eliminará los valores predeterminados del usuario. Mira cuántas personas han votado esta respuesta y verifica tu código. Entonces ve a leer la documentación. Diablos, envíame el código relevante y te mostraré lo que estás haciendo mal. Ha sido así desde iOS 2.0. Voto negativo, pero sugeriría escribir primero un caso de prueba simple y aislado.
Amro

99
No estaría muy seguro de usar NSUserDefault para esto. ¿Por qué? Echa un vistazo a ese hilo: stackoverflow.com/questions/20269116/… . Si inicia su aplicación desde el fondo, hay casos en los que sus claves personalizadas en NSUserDefaults simplemente no están configuradas. ¡Aplicar esta respuesta llevaría a eliminar las llaves personalizadas de su Llavero, aunque realmente no quería eso!
Aurelien Porte

40

Para los usuarios que buscan una versión Swift 3.0 de la respuesta de @ amro:

let userDefaults = UserDefaults.standard

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

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

* tenga en cuenta que la función sincronizar () está en desuso


2
if !userDefaults.bool(forKey: "hasRunBefore") {Es solo más limpio.
nefarianblack

1
La llamada de sincronización debe eliminarse.
Pochi

30

No hay desencadenante para realizar código cuando la aplicación se elimina del dispositivo. El acceso al llavero depende del perfil de aprovisionamiento que se utiliza para firmar la aplicación. Por lo tanto, ninguna otra aplicación podría acceder a esta información en el llavero.

No ayuda con su objetivo eliminar la contraseña en el llavero cuando el usuario elimina la aplicación del dispositivo, pero debería brindarle cierta tranquilidad de que la contraseña no es accesible (solo desde una reinstalación de la aplicación original).


Entonces, si cambiamos el perfil de aprovisionamiento de nuestra aplicación, ¿podría acceder a los valores almacenados previamente en el llavero?
Moaz Saeed

27

Para aquellos que buscan una versión Swift de la respuesta de @ 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

Versión C # Xamarin

    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();
    }

... y para borrar registros del llavero (TODO comentario arriba)

        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
Al usar if (VersionTracking.IsFirstLaunchEver) {// remove keychain items}desde Xamarin.Essentials no necesita el código para userDefaults. Xamarin.Essentials lo envuelve para ti .
Christopher Stephan

7

Los archivos se eliminarán del directorio de documentos de la aplicación cuando el usuario la desinstale. Sabiendo esto, todo lo que tiene que hacer es verificar si existe un archivo como lo primero que sucede application:didFinishLaunchingWithOptions:. Luego, crea incondicionalmente el archivo (incluso si es solo un archivo ficticio).

Si el archivo no existía al momento de la verificación, sabe que esta es la primera ejecución desde la última instalación. Si necesita saber más adelante en la aplicación, guarde el resultado booleano en el miembro delegado de su aplicación.


7

La respuesta de @amro traducida a Swift 4.0:

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

O incluso if !UserDefaults.standard.bool(forKey: "FirstInstall")qué valor predeterminado es falso si la clave no existe. Y .synchronize () no es necesario.
CharlesA

3

Este parece ser el comportamiento predeterminado en iOS 10.3 basado en el comportamiento que las personas han presenciado en la versión beta # 2. Todavía no he encontrado ninguna documentación oficial sobre esto, así que comente si la tiene.


77
Supongo que fue hasta la versión beta 5, el lanzamiento público de iOS 10.3 no contiene este cambio.
Jakub Truhlář
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.