美文网首页iOS 成长之路iOS/MacOS开发IT/互联网
干货:教你用好 Keychain (钥匙串)

干货:教你用好 Keychain (钥匙串)

作者: 腾飞Tenfay | 来源:发表于2020-05-14 23:36 被阅读0次
Keychain Services

Keychain 介绍

Keychain Services 是 macOS 和 iOS 都提供一种安全地存储敏感信息的工具,比如:”网络密码:用于保存访问服务器或者网站,通用密码:用来保存应用程序或者数据库密码“。与此同时,用于认证的证书、密钥和身份信息,也可以存储在 Keychain 中。Keychain Services 的安全机制保证了存储这些敏感信息不会被窃取。简单说来,Keychain 就是一个安全容器。另附 Keychain Services | Apple Developer Documentation

PS: 在 iOS 中 Keychian 依赖用于签名的 provisioning profile 描述文件,确保发布不同版本的时候,使用同一个 provisioning profile 文件。

Keychain Access FTP Server Flow

Keychain 的结构

Keychain 可以包含任意数量的 Keychain item。每一个 Keychain item 包含数据和一组属性。对于一个需要保护的 Keychain item,比如密码或者私钥(用于加密或者解密的 String 字节)数据是加密的,会被 Keychain 保护起来的;对于无需保护的 Keychain item,例如: ”证书,数据未被加密“。

跟 Keychain item 有关系的取决于 item 的类型;应用程序中最常用的是网络密码(Internet passwrods)和普通的密码。正如你所想的,网络密码像安全域(security domain)、协议和路径等一些属性。在 macOS 中,当 keychain 被锁的时候,加密的 item 没办法访问,如果你想要该问被锁的 item,就会弹出一个对话框,需要你输入对应 Keychain 的密码。当然,未有密码的 Keychain 你可以随时访问。但在 iOS 中,你只可以访问你自已的 Keychain items。

Keychain 的特点

  • 数据并不存放在 App 的 Sanbox 中,即使删除了 App,资料依然保存在 Keychain 中。如果重新安装了 App,还可以从 Keychain 获取数据。

  • Keychain 的数据可以用过 Group 方式,让程序可以在 App 间共享。不过得要相同 TeamID

  • Keychain 的数据是经过加密的。

Keychain 的使用

大多数应用需要用到 Keychain, 都用来添加一个密码,修改一个已存在 Keychain item 或者取回密码。

Keychain 提供了以下的操作:

  • SecItemAdd 添加一个 item
  • SecItemUpdate 更新已存在的 item
  • SecItemCopyMatching 搜索一个已存在的item
  • SecItemDelete 删除一个 keychain item

推荐在项目中集成简单好用的 DYFSwiftKeychain,另外,附 Objective-C 版 DYFKeychain

Writing Data

Putting data into a keychain
  • Writing String values
let keychain = DYFSwiftKeychain()
keychain.set("User Account Passcode", forKey: "kUserAccPasscode")
  • Writing Data values
let keychain = DYFSwiftKeychain()
keychain.set(data, forKey: "kCommSecureCode")
  • Writing Boolean values
let keychain = DYFSwiftKeychain()
keychain.set(true, forKey: "kFirstInstalledAndLaunched")

Reading Data

  • Reading String values
let keychain = DYFSwiftKeychain()
let passcode = keychain.get("kUserAccPasscode")
  • Reading Data values
let keychain = DYFSwiftKeychain()
let data = keychain.getData("kCommSecureCode")
  • Reading Boolean values
let keychain = DYFSwiftKeychain()
keychain.getBool("kFirstInstalledAndLaunched")

Deleting Data

let keychain = DYFSwiftKeychain()
let _ = keychain.delete("kFirstInstalledAndLaunched") // Remove single key.
let _ = keychain.clear() // Delete everything from app's Keychain. Does not work on macOS.

Advanced options

Keychain item access
let keychain = DYFSwiftKeychain()
keychain.set("xxx", forKey:"Key1", withAccess: .accessibleWhenUnlocked)

See the list of all available access options.

Synchronizing keychain items with other devices

Note that you do not need to enable iCloud or Keychain Sharing capabilities in your app's target for this feature to work.

// The first device
let keychain = DYFSwiftKeychain()
keychain.synchronizable = true
keychain.set("See you tomorrow!", forKey: "key12")

// The second device
let keychain = DYFSwiftKeychain()
keychain.synchronizable = true
let s = keychain.get("key12") // Returns "See you tomorrow!"

We could not get the Keychain synchronization work on macOS.

Sharing keychain items with other apps

Use accessGroup property to access shared keychain items. In the following example we specify an access group "9ZU3R2F3D4.com.omg.myapp.KeychainGroup" that will be used to set, get and delete an item "key1".

let keychain = DYFSwiftKeychain()
keychain.accessGroup = "9ZU3R2F3D4.com.omg.myapp.KeychainGroup" // Use your own access group.

keychain.set("hello world", forKey: "key1")
keychain.get("key1")
keychain.delete("key1")
keychain.clear()

Note: there is no way of sharing a keychain item between the watchOS 2.0 and its paired device: https://forums.developer.apple.com/thread/5938

Returning data as reference

Use the asReference: true parameter to return the data as reference, which is needed for NEVPNProtocol.

let keychain = DYFSwiftKeychain()
keychain.set(data, forKey: "key1")
keychain.getData("key1", asReference: true)

关于共享 Keychain 的数据可以透过 Group Access 的方式,让资料可以在 App 间共享,Google 系列的 App (Gmail、Google+、日历…) 就是通过这样的方式来记录使用者登入信息,只要使用者在其中一个 App 中完成登入了,其他的 App 也可以读取到相同的登入数据进行登录。

进入 Capabilities,打开 Keychain Sharing

Keychain Sharing

开启 Keychain 后,会自动新增一个 Keychain Group,使用的是 Bundle Identifier。 同时也会自动新增一个 entitlements 文件,里面也会有一个 Access Group,名为 $(AppIdentifierPrefix)+Your Bundle Identifier

Keychain Group entitlements

(AppIdentifierPrefix) 是开发者的账号需要登录才会有,也就是开发者证书后小括号内的英文数字组合。使用 $(AppIdentifierPrefix) 只能被同一个开发者账号的 App 来存取,以防被有心人盗取。

Xcode Signing

若其他的 App 也要存取当前 Keychain 的数据,就必需在 Keychain 开启后,新增相同的 Keychain Group (Access Group 会根据 Keychain Group 自动新增)。

PS: 需要 Info.plist 新增一对键值 Key: AppIdentifierPrefix,Value: $(AppIdentifierPrefix),方便取得 Identifier Prefix

总结:写的有不好的地方希望大家指出,我会更正,大家有什么看不明白的,也可以在评论里面提问,我会尽力解答。另附 Apple 官方 GenericKeychain


点赞+关注,第一时间获取技术干货和最新知识点,谢谢你的支持!转发请注明出处

最后祝大家生活愉快~

相关文章

网友评论

    本文标题:干货:教你用好 Keychain (钥匙串)

    本文链接:https://www.haomeiwen.com/subject/tqifjctx.html