安全地将密码密钥存储在iOS钥匙串中

在我的安全系列#1中,移动安全。 我已经介绍了移动安全性的基本知识。 现在,让我们弄脏双手。 让我简要介绍一下如何在iOS钥匙串系统中创建和存储加密密钥。

开始使用

加密密钥应存放在安全的地方。 密钥存储不当会导致数据泄露。 在iOS中,有两个框架可确保加密密钥的安全性。

  1. 本地认证框架
  2. 安全框架

在本文中,我将介绍两者并解释它们如何通过结合使用这两个框架来保护加密密钥。

本地认证框架

本地身份验证框架用于管理生物识别,例如TouchID和FaceID。

本地身份验证框架不允许应用访问系统内部的生物特征数据。 它就像在应用程序和硬件支持的安全区域之间进行通信的代理一样。

本地身份验证框架使应用程序需要用户存在才能访问敏感信息,例如加密密钥。

LAContext是本地身份验证框架中的类,用于桥接应用程序和保护安全区域。

  LAContext()。evaluatePolicy( 
LAPolicy.deviceOwnerAuthenticationWithBiometrics,
localizedReason:“原因”){(成功,错误)在
  //处理返回 
  } 

但是,以上方法不足以保护敏感数据。 它只是提示您评估用户的指纹或面部。 为了保护敏感数据,我们应该通过安全框架将敏感数据存储到钥匙串中。

安全框架

安全框架提供了一些方法来生成加密密钥,将系统密钥链中的密钥存储和检索为Keychain Item

要生成密钥对,我们可以调用以下方法:

  // 1.创建密钥访问控制 
 守护让accessControl = 
SecAccessControlCreateWithFlags(
kCFAllocatorDefault,
kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
[.privateKeyUsage,.biometryCurrentSet],
零)
其他{
fatalError(“无法设置访问控制”)
}
  // 2.创建关键属性 
  let属性:[String:任何] = [ 
kSecClass作为字符串:kSecClassKey,
kSecAttrKeyType作为字符串:kSecAttrKeyTypeRSA
kSecAttrKeySizeInBits作为字符串:2048,
kSecPrivateKeyAttrs作为字符串:[
kSecAttrIsPermanent as String:true,
kSecAttrApplicationTag作为字符串:“ com.mydomian.uniqueTag”,
kSecAttrAccessControl作为字符串:accessControl
]
]
  // 3.生成密钥对 
  var错误:Unmanaged ? 
守护让privateKey =
SecKeyCreateRandomKey(归因于CFDictionary,&error)else {
//抛出错误
}
  1. 为密钥创建访问控制kSecAttrAccessibleWhenUnlockedThisDeviceOnly是密钥的可访问性设置。 这意味着应用程序只能在特定设备解锁后才能访问钥匙串项。 .privateKeyUsage.biometryCurrentSet是身份验证设置。 要使用钥匙串物品,用户必须提供生物特征认证。
  2. 创建密钥属性,密钥类型(如kSecAttrKeyTypeRSA和密钥大小2048指示密钥的类型。 kSecPrivateKeyAttrs用于描述私钥。 步骤1中设置的访问控制应在此处设置。 kSecAttrApplicationTag是用于检索的唯一标识符。 这里重要的是kSecAttrIsPermanent 。 它指示生成密钥时,私钥将隐式存储到默认密钥链存储中。
  3. 生成私钥

为了从私钥中获取公钥,安全框架提供了一种方法

 让publicKey = SecKeyCopyPublicKey(privateKey) 

生成并存储私钥后,让我们尝试检索要使用的密钥。 由于我们已使用私钥设置了可访问性和身份验证设置,因此当应用程序请求获取密钥时,基于上述设置,可访问性可确保只有相同的设备和未锁定的设备状态才能访问该私钥。 此外,身份验证设置可确保通过显示系统生物身份验证对话框以验证用户存在状态来验证同一组生物数据。

有代码:

  // 1.进行搜索查询 
让查询:[字符串:任何] = [
kSecClass作为字符串:kSecClassKey,
kSecAttrKeyClass作为字符串:kSecAttrKeyClassPrivate,
kSecAttrKeyType作为字符串:kSecAttrKeyTypeRSA,
kSecAttrKeySizeInBits作为字符串:2048,
kSecAttrApplicationTag作为字符串:“ com.mydomian.uniqueTag”,
kSecReturnRef作为字符串:true
]
  // 2.复制密钥参考 
  var项目:CFTypeRef? 
let status = SecItemCopyMatching(以CFDictionary,&item查询)
防护状态== errSecSuccess其他{
返回零
}
  1. 创建搜索查询以查找关键字。 kSecReturnRef表示仅返回私钥引用。
  2. 执行搜索并获取私钥参考。

iOS的另一项保护措施是,仅检索私钥引用,而不检索整个私钥数据。 关键数据安全地存储在安全区域中,并且无法复制到应用程序内存中。

iOS Secure Enclave支持在安全硬件内部创建密钥。 专用密钥的创建和数据在分离的CPU,RAM安全区域中进行。 由于硬件支持的隔离环境提供了最高级别的安全性,因此大大提高了安全性级别。 但是,iOS安全区域仅支持一种密钥类型,即256位椭圆曲线私钥。

在Secure Enclave中存储密钥的密钥属性:

  let属性:[String:任何] = [ 
kSecClass作为字符串:kSecClassKey,
kSecAttrKeyType作为字符串: kSecAttrKeyTypeECSECPrimeRandom
kSecAttrKeySizeInBits作为字符串: 256
kSecAttrTokenID作为字符串:kSecAttrTokenIDSecureEnclave
kSecPrivateKeyAttrs作为字符串:[
kSecAttrIsPermanent as String:true,
kSecAttrApplicationTag作为字符串:“ com.mydomian.uniqueTag”,
kSecAttrAccessControl作为字符串:accessControl
]
]

高亮部分显示了使用的256位椭圆曲线私钥。 有一个名为kSecAttrTokenID的附加属性。 它使密钥可以存储在安全的区域中。

结论

本地身份验证和安全框架中仍然存在一些方法来帮助我们管理密码密钥。 通过启用钥匙串访问组之类的功能,我们可以在我们的应用程序包中安全地共享凭据。

希望本文能激发您的灵感,并为您介绍在您的应用中实现钥匙串API的介绍。 如果您觉得这篇文章有帮助,请给我鼓掌