卸载应用程序时删除钥匙串项

Posted

技术标签:

【中文标题】卸载应用程序时删除钥匙串项【英文标题】:Delete keychain items when an app is uninstalled 【发布时间】:2011-06-12 10:56:08 【问题描述】:

我正在使用idandersen's scifihifi-iphone 代码作为钥匙串并使用

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

当我从设备中删除应用程序时,密码仍保留在钥匙串中。

当用户从设备中删除应用程序时,我想从钥匙串中删除密码。我该怎么做?

【问题讨论】:

由于您的应用程序被删除时您的代码没有运行,因此您无法执行此操作。 我认为您只能从应用程序内部删除钥匙串项目,但不能在卸载之前删除它。您可以查看 SFHFKeychainUtils 的 deleteItem 方法来从钥匙串中删除用户名或密码。 【参考方案1】:

您可以利用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

如果尚未设置,这会在您的应用首次运行时检查并设置 NSUserDefaults 中的“FirstRun”键/值。有一条注释,您应该在其中放置代码以从钥匙串中删除值。可以调用 Synchronize 以确保“FirstRun”键/值立即持久化,以防用户在系统持久化之前手动终止应用程序。

【讨论】:

我同意 Amro 的观点,即您可以在第一次运行应用程序时删除/清除您的钥匙串。这将清除上次卸载应用程序之前设置的所有内容。我为我的一个存储 Facebook/Twitter 凭据的应用程序执行了此操作,并且知道只有您的应用程序可以访问设置的任何钥匙串这一事实,它运行良好。 NSUserDefaults 在用户手动退出应用时不会被清除。在这种情况下,只有您设置但系统(定期)或尚未与磁盘同步(通过调用synchronize)的值会丢失。在设置第一个运行键后调用同步是个好主意。是的,当设备被重置(而不是从备份中恢复)时,NSUserDefaults 会被清除,在这种情况下这很好。 你错了,你可能正在做一些导致用户默认值被清除的事情。 NSUserDefaults 的全部意义在于保存首选项并让这些首选项在多个应用程序启动时保持不变。同样,重置设备或删除应用程序将删除用户默认设置。看看有多少人对这个答案投了赞成票并检查你的代码。然后去阅读文档。哎呀,把相关代码发给我,我会显示你做错了什么。从 ios 2.0 开始就是这样。否决票,但我建议先编写一个孤立的、简单的测试用例。 P.S.还有一篇文章详细解释了chrisrisner.com/… 我对为此使用 NSUserDefault 不是很有信心。为什么?看看那个线程:***.com/questions/20269116/…。如果您从后台启动您的应用程序,在某些情况下您的 NSUserDefaults 中的自定义键没有设置。应用此答案会导致删除您的钥匙串自定义键,尽管您真的不希望这样做!【参考方案2】:

对于寻找@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() 函数已弃用

【讨论】:

if !userDefaults.bool(forKey: "hasRunBefore") 更干净了。 同步调用应该被移除。【参考方案3】:

从设备中删除应用时,不会触发执行代码。对钥匙串的访问取决于用于签署应用程序的配置文件。因此,没有其他应用程序能够访问钥匙串中的此信息。

当用户从设备中删除应用程序时,它不会帮助您删除钥匙串中的密码,但它应该让您感到安慰的是密码无法访问(仅通过重新安装原始应用程序) .

【讨论】:

那么,如果我们更改应用程序的配置文件,它是否能够访问之前存储在钥匙串中的值。 @MoazSaeed 根据我的经验,即使配置文件发生变化,该应用程序也可以访问之前存储在 Keychain 中的值。【参考方案4】:

对于那些正在寻找@amro 答案的 Swift 版本的人:

    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
    

【讨论】:

【参考方案5】:

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

【讨论】:

通过使用 Xamarin.Essentials 中的 if (VersionTracking.IsFirstLaunchEver) // remove keychain items,您不需要 userDefaults 的代码。 Xamarin.Essentials wraps that for you.【参考方案6】:

当用户卸载应用程序时,文件将从应用程序的文档目录中删除。知道了这一点,您所要做的就是检查文件是否存在作为application:didFinishLaunchingWithOptions: 中发生的第一件事。之后,无条件地创建文件(即使它只是一个虚拟文件)。

如果在检查时该文件不存在,您就知道这是自最新安装以来的第一次运行。如果您需要稍后在应用程序中知道,请将布尔结果保存到您的应用程序委托成员。

【讨论】:

【参考方案7】:

@amro's answer 翻译成 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()。【参考方案8】:

这似乎是 iOS 10.3 上的默认行为,基于 beta #2 中的行为 people have been witnessing。尚未找到任何有关此的官方文档,因此如果有,请发表评论。

【讨论】:

我猜在 beta 5 之前,iOS 10.3 的公开版本包含此更改。【参考方案9】:

只需添加一个应用设置包并实现切换以在应用重启时重置钥匙串或基于通过设置选择的值(可通过 userDefaults 获得)

【讨论】:

以上是关于卸载应用程序时删除钥匙串项的主要内容,如果未能解决你的问题,请参考以下文章

使用 LAContext 和 touchIDAuthenticationAllowableReuseDuration 获取钥匙串项

卸载 iOS 应用程序时删除钥匙串

NSInternalInconsistencyException:无法更新钥匙串项

未设置访问组时共享的钥匙串项目

苹果密码钥匙串在哪里

在钥匙串中存储凭据不仅加密密码