Удалить элементы цепочки для ключей при удалении приложения

238

Я использую код scifihifi-iphone от idandersen для связки ключей и сохраняю пароль, используя

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

Когда я удаляю приложение с устройства, пароль остается в связке ключей.

Я хочу удалить пароль из цепочки для ключей, когда пользователь удаляет приложение с устройства. Как я могу это сделать?

прил
источник
13
Поскольку ваш код не запускается при удалении вашего приложения, у вас нет возможности сделать это.
Джонатан Гринспан
1
Я думаю, что вы можете удалить элемент цепочки для ключей только из приложения, но не перед его удалением. Вы можете взглянуть на метод deleteItem в SFHFKeychainUtils, чтобы удалить имя пользователя или пароль из цепочки для ключей.
matteodv

Ответы:

406

Вы можете воспользоваться тем , что NSUserDefaults имеют очищенные от деинсталляции приложения. Например:

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

Это проверяет и устанавливает ключ / значение «FirstRun» NSUserDefaultsпри первом запуске вашего приложения, если оно еще не установлено. Там есть комментарий, где вы должны поместить код для удаления значений из цепочки для ключей. Синхронизация может быть вызвана, чтобы убедиться, что ключ / значение «FirstRun» немедленно сохраняется в случае, если пользователь убивает приложение вручную до того, как система его сохранит.

Amro
источник
2
Я согласен с Amro, что вы можете удалить / очистить цепочку для ключей при первом запуске приложения. Это очистит все, что было установлено до последнего удаления приложения. Я сделал это для одного из моих приложений, в котором хранятся учетные данные Facebook / Twitter, и он работал довольно хорошо, зная тот факт, что только ваше приложение имеет доступ к любой установленной цепочке для ключей.
XCool
Спасибо за этот совет.
iOSAppDev
3
NSUserDefaults не очищаются, когда пользователь вручную выходит из приложения. В synchronizeэтом случае будут потеряны только те значения, которые вы установили, но либо система (периодически), либо еще не синхронизированная с диском (путем вызова ). Рекомендуется вызвать синхронизацию после установки первого ключа запуска. И да, NSUserDefaults очищаются, когда устройство перезагружается (а не восстанавливается из резервной копии), и это нормально в этом случае.
Amro
5
Вы ошибаетесь и, вероятно, делаете что-то, что приводит к очистке пользовательских настроек по умолчанию. Весь смысл NSUserDefaults состоит в том, чтобы сохранить настройки и сохранить их в течение нескольких запусков приложений. Снова, сброс устройства или удаление приложения удалит пользовательские настройки по умолчанию. Посмотрите, сколько людей проголосовали за этот ответ, и проверьте ваш код. Тогда иди почитай документацию. Heck, пришлите мне соответствующий код и я показать вам , что вы делаете неправильно. Так было с iOS 2.0. Откажитесь от голосования, но я бы предложил сначала написать отдельный простой тестовый пример.
Amro
9
Я не был бы очень уверен в использовании NSUserDefault для этого. Зачем? Посмотрите на эту ветку: stackoverflow.com/questions/20269116/… . Если вы запускаете свое приложение из фона, есть случаи, когда ваши пользовательские ключи в NSUserDefaults просто не установлены. Применение этого ответа приведет к удалению ваших пользовательских ключей Keychain, хотя вы действительно этого не хотите!
Aurelien Porte
40

Для пользователей, которые ищут версию @ amro от Swift 3.0 :

let userDefaults = UserDefaults.standard

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

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

* обратите внимание, что функция synchronize () устарела

bwcooley
источник
2
if !userDefaults.bool(forKey: "hasRunBefore") {Это просто чище.
nefarianblack
1
Синхронизировать вызов следует удалить.
Почи
30

Нет триггера для выполнения кода при удалении приложения с устройства. Доступ к цепочке для ключей зависит от профиля обеспечения, который используется для подписи приложения. Поэтому никакие другие приложения не смогут получить доступ к этой информации в цепочке для ключей.

Это не поможет вам удалить пароль из цепочки для ключей, когда пользователь удаляет приложение с устройства, но должно дать вам некоторое утешение, что пароль недоступен (только после переустановки исходного приложения).

Шейн Фитцгиббон
источник
Таким образом, если мы изменим профиль обеспечения нашего приложения, сможет ли он получить доступ к ранее сохраненным значениям в цепочке для ключей.
Моаз Саид
27

Для тех, кто ищет Swift-версию ответа @ 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
    }
RSC
источник
9

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

... и очистить записи из цепочки для ключей (комментарий TODO выше)

        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);
        }
InquisitorJax
источник
1
При использовании if (VersionTracking.IsFirstLaunchEver) {// remove keychain items}из Xamarin.Essentials вам не нужен код для userDefaults. Xamarin.Essentials оборачивает это для вас .
Кристофер Стефан
7

Файлы будут удалены из каталога документов вашего приложения, когда пользователь удалит приложение. Зная это, все, что вам нужно сделать, это проверить, существует ли файл как первое, что происходит в application:didFinishLaunchingWithOptions:. После этого безоговорочно создайте файл (даже если это просто фиктивный файл).

Если файл не существовал на момент проверки, вы знаете, что это первый запуск с момента последней установки. Если вам нужно узнать об этом позже в приложении, сохраните логический результат в делегате вашего приложения.

Стивен
источник
7

Ответ @ amro переведен на Swift 4.0:

if UserDefaults.standard.object(forKey: "FirstInstall") == nil {
    UserDefaults.standard.set(false, forKey: "FirstInstall")
    UserDefaults.standard.synchronize()
}
Мухаммед Наяб
источник
Или даже if !UserDefaults.standard.bool(forKey: "FirstInstall")который по умолчанию имеет значение false, если ключ не существует. И .synchronize () не нужен.
CharlesA
3

Похоже, что это поведение по умолчанию на iOS 10.3, основанное на поведении, которое люди наблюдали в бета-версии 2. Официальной документации по этому вопросу пока не найдено, поэтому, пожалуйста, оставьте комментарий.

Stavash
источник
7
Это было до бета 5, я думаю, публичный релиз iOS 10.3 не содержит этого изменения.
Якуб Трухларж