如何删除应用程序可以访问的所有钥匙串项目?

56

我在iOS上有一些杂项钥匙串项目(可能是由旧版本的应用程序编写),我需要将其删除。 有没有简单的方法来实现这个?


1
请参考https://dev59.com/l2gu5IYBdhLWcg3w8Lav获取您可以访问的所有项目,然后逐个删除。 - Daij-Djan
我正在寻找一种方法,在我的iPhone上删除特定应用程序的钥匙串项目。我真的需要它,因为这些应用程序不是由我开发的。 - DawnSong
8个回答

93

为所有类执行此操作

Objective-C:

NSArray *secItemClasses = @[(__bridge id)kSecClassGenericPassword,
                       (__bridge id)kSecClassInternetPassword,
                       (__bridge id)kSecClassCertificate,
                       (__bridge id)kSecClassKey,
                       (__bridge id)kSecClassIdentity];
for (id secItemClass in secItemClasses) {
    NSDictionary *spec = @{(__bridge id)kSecClass: secItemClass};
    SecItemDelete((__bridge CFDictionaryRef)spec);
}

迅捷:

      [kSecClassGenericPassword, kSecClassInternetPassword, kSecClassCertificate, kSecClassKey, kSecClassIdentity].forEach {
        let status = SecItemDelete([
          kSecClass: $0,
          kSecAttrSynchronizable: kSecAttrSynchronizableAny
        ] as CFDictionary)
        if status != errSecSuccess && status != errSecItemNotFound {
            //Error while removing class $0
        }
      }

我在NSDictionary中使用了一个字面量,所以它需要xcode4.5+,但如果有人需要旧的gcc/llvm支持,则可以使用dictionaryWithObject:forKey:。 - Daij-Djan
4
那不是一个字典文字,应该是NSDictionary *spec = @{(__bridge id)kSecClass: secItemClass}; - kevboh
1
错别字还没有修复。需要按照kevboh指定的方式,在kSecClass之前移动转换。 - Jeremie Weldin
最近的踩票者,您能否留下一条评论,以便我在需要时进行修复。 - Daij-Djan
我认为 kSecAttrAccount 缺失了。 - RolandasR
我正在使用开放式Office 365登录,但我的oauth2库没有注销Keychain。如果有任何想法,请在此处评论。 - Digvijaysinh Gida

15

Xamarin iOS版本(MonoTouch)接受的答案关于如何删除应用程序可以访问的所有钥匙串项目如下:

foreach (var recordKind in new []{
                SecKind.GenericPassword,
                SecKind.Certificate,
                SecKind.Identity,
                SecKind.InternetPassword,
                SecKind.Key,
            })
    {
          SecRecord query = new SecRecord(recordKind);
          SecKeyChain.Remove(query);
    }
如果您想确保您确实删除了记录,您可以在开发过程中使用以下代码检查特定类型的KeyChain中的项目数量(删除前后):during development
SecStatusCode scc;
var records = SecKeyChain.QueryAsRecord(new SecRecord(SecKind.GenericPassword), 1000, out scc);

14

我用Swift重写了Daij-Djan的答案:

let secItemClasses = [kSecClassGenericPassword,
    kSecClassInternetPassword,
    kSecClassCertificate,
    kSecClassKey,
    kSecClassIdentity]
for secItemClass in secItemClasses {
    let dictionary = [kSecClass as String:secItemClass]
    SecItemDelete(dictionary as CFDictionary)
}

这段代码导致了我的程序崩溃。问题出现在 hashValue 变量中的 CFHash 转 Int 转换上(至少在 32 位平台上)。CFHash 返回一个 UINT,当在 Swift 中转换为 Int 时可能会溢出。我建议将该行更改为 public var hashValue: Int {return Int(bitPattern:CFHash(self))} 以确保不会发生溢出。 - Brett
1
CFString与NSString之间存在免费桥接,而NSString又与Swift字符串之间存在桥接,因此您可以直接进行强制转换,例如:let dictionary = [kSecClass as String : secItemClass as String] - Brandon
3
除非您编写“SecItemDelete(字典作为CFDictionary)”,否则Swift 3编译器将会报错。 - John Difool

12

Swift版本

import Foundation
import Security


public class Keychain: NSObject {
  public class func logout()  {
    let secItemClasses =  [
      kSecClassGenericPassword,
      kSecClassInternetPassword,
      kSecClassCertificate,
      kSecClassKey,
      kSecClassIdentity,
    ]
    for itemClass in secItemClasses {
      let spec: NSDictionary = [kSecClass: itemClass]
      SecItemDelete(spec)
    }
  }
}

用法:

Keychain.logout()

2
我喜欢这个解决方案,因为它有一个API。 - Alan Andrade
感谢 @AlanAndrade - ScottyBlades

7
感谢Daij-Djan,我找到了这个解决方案:
for (id secclass in @[
     (__bridge id)kSecClassGenericPassword,
     (__bridge id)kSecClassInternetPassword,
     (__bridge id)kSecClassCertificate,
     (__bridge id)kSecClassKey,
     (__bridge id)kSecClassIdentity]) {
    NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                  secclass, (__bridge id)kSecClass,
                                  nil];

    SecItemDelete((__bridge CFDictionaryRef)query);        
}

我现在也得到了同样的结果:D 嘿嘿 - Daij-Djan
很高兴看到这次楼主和你一起合作回答 :) - Daij-Djan

5
很遗憾,这个问题的所有答案似乎都已经过时(自iOS 7.0+以来) ,因为它们没有删除设置了 kSecAttrSynchronizable 标志的密钥链条目(通过iCloud允许与其他设备同步)。
要删除这样的条目,必须向DELETE查询添加一个条目,并指定 kSecAttrSynchronizable: kSecAttrSynchronizableAny
Swift 版本:
let secItemClasses = [kSecClassGenericPassword,
    kSecClassInternetPassword,
    kSecClassCertificate,
    kSecClassKey,
    kSecClassIdentity]
for secItemClass in secItemClasses {
    let query: NSDictionary = [
        kSecClass as String: secItemClass,
        kSecAttrSynchronizable as String: kSecAttrSynchronizableAny
    ]
    SecItemDelete(query)
}

1
你可以查看 Utilities 文件夹中找到的 KeyChain Access 应用程序。如果你启动该应用程序并点击“所有项目”,它应该显示在此台计算机上创建的所有项。开发者通常以 com 开头。

2
对于 Mac,你的答案是完美的,但在 iOS 上,Keychain Access 应用程序不存在。无论如何,谢谢! - sqreept
这是一个好主意,但是似乎我在 Mac 上无法访问 iPhone 上特定应用程序的钥匙串项目,尽管我已经将我的钥匙串存储在 iCloud 上。 - DawnSong
我正在寻找手动删除特定应用程序的钥匙串的方法。 - DawnSong

0

在使用 Mac 作为目标进行单元测试时,谨慎使用 kSecClassCertificate 来清除所有内容,因为这将清除您的开发证书。您可以简单地撤销现有证书,但在 CI/CD 管道中,这种方法行不通。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接