1 Article|Sharing Access to Keychain Items Among a Collection of Apps 文章|多个应用共享钥匙链项目
Enable apps to share keychain items with each other by adding the apps to an access group.
将多个应用加入到一个访问组,实现多应用之间互相共享钥匙链项目
2 Overview概述
If you develop a family of apps, all of which rely on the same user secret, you can use access groups to securely share that secret among those apps. For example, you can share credentials, so that logging into one of your apps automatically grants the user access to all of your apps. This kind of sharing doesn’t require interaction with or permission from the user, but limits sharing to apps that are delivered by a single development team.
如果我们开发了一系列应用,而这些应用都使用同一个用户私密信息,可以使用访问组来安全地在这些应用之间共享这些私密信息.例如,你可以共享证书,以便用户登录一个应用后,会授予用户访问所有应用的权限.这种共享不需要与用户交互或获得用户的许可,而是将共享限制为由同一个开发团队开发的应用。
An access group is a logical collection of apps tagged with a particular group name string. Any app in a given group can share keychain items with all the other apps in the same group. You can add an app to any number of groups, but the app is always part of at least one group that contains only itself. That is, an app can always store and retrieve private keychain items, regardless of whether it also participates in any other groups. Keychain items, on the other hand, are always part of exactly one group.
访问组是用特定组名字符串标记的应用程序的逻辑集合。给定组中的任何应用都可以与同一组中的所有其他应用共享钥匙链项目。可以将应用程序添加到任意数量的组中,但该应用程序始终是至少一个仅包含其自身的组的一部分。也就是说,应用程序始终可以存储和检索私有的钥匙链项目,而不管它是否也参与任何其他组。另一方面,钥匙链项目总是只属于一个组的.
Important重点:
This form of keychain item sharing applies to all iOS keychain items, and to macOS keychain items when you query with the kSecUseDataProtectionKeychain key, set the item’s kSecAttrSynchronizable attribute, or both.
这种形式的钥匙链项目共享适用于所有iOS钥匙链项目,如果要适用于macOS密钥链项目,需要设置kSecUseDataProtectionKeychain键,或者kSecAttrSynchronizable属性,或者两者都设置.
2.1 Set Your App’s Access Groups
You control the groups that your app belongs to by manipulating its entitlements. In particular, an app belongs to all the groups named in a virtual array of strings that the system forms for each app as the concatenation of the following items, evaluated in this order:
我们通过操纵应用程序的 权限文件 来控制其所属的组。特别地,应用程序属于虚拟字符串数组中命名的所有组,系统为每个应用程序形成字符串数组,作为以下项的连接,按此顺序计算:
Keychain access groups 钥匙链访问组
The optional Keychain Access Groups Entitlement holds an array of strings, each of which names an access group.
可选的 钥匙链访问组权限文件 中指定了一个字符串数组,每个字符串代表一个访问组.Application identifier
Xcode automatically adds the application-identifier entitlement (or the com.apple.application-identifier entitlement in macOS) to every app during code signing, formed as the team identifier (team ID) plus the bundle identifier (bundle ID).
Xcode在代码签名时自动为每个app添加了一个 application-identifier entitlement (如果是macOS的话,是com.apple.application-identifier entitlement),有teamId加上bundleId组成.Application groups 应用组
When you collect related apps into an application group using the App Groups Entitlement, they share access to a group container, and gain the ability to message each other in certain ways. Starting in iOS 8, the array of strings given by this entitlement also extends the list of keychain access groups.
当我们使用 应用组权限文件 把相关联的多个应用设置为一个 应用组 时,这些应用可以共享访问一个组容器,可以通过特定方式互相发送消息.从iOS8开始,应用组权限文件中指定的字符串数组同时扩展了钥匙链访问组.
Xcode handles the application identifier (app ID) for you when you set the bundle ID. You set the others by manipulating capabilities in Xcode.
Xcode在你设置bundleID时,自动将该应用添加到了一个以该appID相同的钥匙链访问组中.而其他的访问组,需要通过在Xcode操作capabilities菜单来设置.
2.2 Establish Your App’s Private Access Group设置应用的钥匙链私有访问组
One of the first steps you take when you create any new app is to assign it a bundle ID, typically using reverse DNS notation, with a string like com.example.AppOne. When code signing your app, Xcode automatically prefixes the bundle ID with your team ID—the unique character sequence issued by Apple to each development team—and stores the combined string as the app ID. The system recognizes this app ID as the name of your app’s private access group by including it in your access group array:
创建应用的第一步就是为应用分配一个bundleID,通常我们使用 反向域名标记法 ,名称通常类似于com.example.AppOne
.当Xcode对应用代码签名时,会自动存储一个AppId,该AppId是由TeamId加上BundleId组合而成.TeamId是苹果为每个开发团队分配的一个唯一字符续序列.系统将该AppId添加到访问组名称数组中,并将它作为应用的私有钥匙链访问组的组名:
[$(teamID).com.example.AppOne]
Because app IDs are unique across all apps, and because the app ID is stored in an entitlement protected by code signing, no other app can use it, and so no other app is in this group. Any keychain items stored with this access group are private to App One. Similarly, if you have a second app with a bundle ID of com.example.AppTwo, it automatically belongs to its own private group:
因为引用的AppId是唯一的,并且存储于由代码签名保护的权限文件中,其他应用不能使用,并且该访问组中不存在其他应用.任何在该访问组中建立的钥匙链项目都是AppOne私有的.同样地,如果我们创建第二个应用,BundleId为:com.example.AppTwo
,它会被自动地添加到它的私有访问组中:
[$(teamID).com.example.AppTwo]
As a result, by default, each app’s keychain items remains isolated from all other apps.
默认结果就是,每个应用的钥匙链项目都是和其他应用孤立的.
2.3 Add Apps to One or More Keychain Access Groups将应用添加到多个钥匙链访问组中
When you want two apps to be able to share keychain items, you can add both to the same keychain access group. Do this by enabling the Keychain Sharing capability in Xcode for each app, and adding a common string to the list of keychain groups in each case. Typically, you use the same kind of reverse DNS naming for a keychain group that you use for a bundle ID, so you might choose com.example.SharedItems:
如果想让两个应用共享钥匙链项目,需要把两个应用都加到同一个钥匙链访问组中.需要在Xcode中为每个应用开启Keychain Sharing capability,并且为两个应用在钥匙链访问组中添加同一个字符串.通常,使用和BundleId类似的反向域名命名法来命名这个钥匙链访问组,例如`com.example.SharedItems':
As with forming the app ID from the bundle ID, Xcode automatically prefixes keychain groups with your team ID. This ensures that your groups are specific to your development team. When you enable the capability for App One as shown above, its logical list of app groups becomes:
Xcode会自动在设置的钥匙链访问组名称上加上TeamId前缀,就像形成AppId的方式那样.这确保了访问组是特定于一个开发者团队的.当你为AppOne开启了上述的功能,它的逻辑访问组列表就是:
[$(teamID).com.example.SharedItems,
$(teamID).com.example.AppOne]
If you also add the same keychain group to App Two, its logical list of app groups becomes:
如果为AppTwo添加了一样的钥匙链访问组,那么它的逻辑访问组列表就是:
[$(teamID).com.example.SharedItems,
$(teamID).com.example.AppTwo]
In effect, the two apps gain a region of overlap to share items.
最终,这两个应用增加了一个共通的区域来共享钥匙链项目.
2.4 Use App Groups to Expand Sharing of Keychain and Non-Keychain Data使用应用组来扩展钥匙链和非钥匙链数据的共享
When your app belongs to an app group, it can share certain kinds of non-keychain data with other apps in the same group. For example, you can use the initWithSuiteName: method to create a new NSUserDefaults instance that shares the preferences you set among all the apps in the app group. Like keychain access groups, you enable app groups with a capability in Xcode.
当一个应用属于一个 应用组,它可以和该组中的其他应用共享特定种类的非钥匙链数据.例如,可以使用initWithSuiteName
方法来创建一个NSUserDefaults实例来在应用组的所有应用中共享偏好设置.和钥匙链访问组一样,需要在Xcode capability菜单中开启应用组功能.
Starting in iOS 8, when an app belongs to an app group, it can also use this mechanism to share keychain items. In this example, add App One to the group.com.example.AppSuite app group:
从iOS8开始,当一个应用属于一个应用组,那么它们也能共享钥匙链项目.在此例中,添加AppOne到group.com.example.AppSuite应用组:
App One’s list of access groups expands to include the app group:
AppOne的钥匙链访问组就会包含应用组中的设置:
[$(teamID).com.example.SharedItems,
$(teamID).com.example.AppOne,
group.com.example.AppSuite]
This allows it to share keychain items with any app in the App Suite group (distinct from any sharing it’s already doing with apps in the shared items keychain access group).
这让它可以和AppSuite组内的任何其他应用共享钥匙链项目(这和与钥匙链访问组内的其他App共享有所不同).
Xcode doesn’t prepend the app group with the team identifier. Instead, it guards against the reuse of app group names across teams when you try to add an app group to a provisioning profile.
Xcode不会在应用程序组前面加TeamId。相反,当你添加应用组到描述文件时,会防止你在多个开发团队间使用多个应用组名称.
2.5 Know the Difference Between App Groups and Keychain Access Groups区别应用组和钥匙链访问组
App groups and keychain access groups aren’t mutually exclusive—you can use both in the same app—but they do differ in several important ways that may help you decide which to use for a given situation.
应用组和钥匙链访问组之间不是互斥的.可以在一个应用中使用两者.但是它们在某些重要方面是不同的,我们需要在特定场合决定使用哪种方案.
First, as described above, using an app group enables additional data sharing beyond keychain items. You might want this extra sharing, or might already be using an app group for this purpose, and thus not need to add keychain access groups. On the other hand, you might not want to enable this additional sharing at all, and prefer keychain access groups instead.
首先,如前面所描述的,应用组可以实现出了钥匙链项目以外的附加数据的共享.如果你需要附加的数据共享,或者你已经在使用应用组功能了,就没必要再使用钥匙链访问组功能了.另一方面,如果我们根本不需要附加数据共享,我们就应该选择钥匙链访问组替代.
Second, order matters. The system considers the first item in the list of access groups to be the app’s default access group. This is the access group that keychain services assumes if you don’t otherwise specify one when adding keychain items. An app group can’t ever be the default, because the app ID is always present and appears earlier in the list. However, a keychain access group can be the default, because it appears before the app ID. In particular, the first keychain access group, if any, that you specify in the corresponding capability becomes the app’s default access group. If you don’t specify any keychain access groups, then the app ID is the default.
第二,他们之间有顺序的不同.系统默认将钥匙链访问组列表中的第一个作为默认访问组.如果在添加钥匙链项目时不指定访问组,系统将它加入默认访问组.应用组是不会成为默认访问组的,因为AppId总是会在应用组名称的前面.然而,钥匙链访问组会成为默认的,因为它出现在AppId前面.特别低,当你添加钥匙链访问组,那么第一个就是默认的访问组.如果你没有添加钥匙链访问组,那么名称为AppId的访问组就是默认的访问组.
2.6 Set a Keychain Item’s Access Group设置钥匙链项目的访问组.
Unlike apps, which can belong to many access groups, keychain items belong to a single group, identified by the kSecAttrAccessGroup attribute. From the item’s point of view, the world is a collection of disjoint groups, and the item belongs to exactly one of them.
和应用不同,应用可以属于多个访问组,但是钥匙链项目只能属于一个访问组,由kSecAttrAccessGroup属性标识.从钥匙链项目的视角来看,这个世界是不相交的集合,项目只能属于其中一个集合.
When you create a new item with the SecItemAdd method, you can specify a group in the add attributes using the kSecAttrAccessGroup key. For example, you can create a new generic password item in the Shared Items group defined above:
当你用SecItemAdd方法创建了一个新的钥匙链项目,可以用kSecAttrAccessGroup键来指定它所属的访问组.例如,可以创建一个通用密码类型的项目,并将其添加到前面定义的SharedItems访问组中:
let accessGroup = "<# Your Team ID #>.com.example.SharedItems"
let attributes = [kSecClass: kSecClassGenericPassword,
kSecAttrService: service,
kSecAttrAccount: username,
kSecAttrAccessGroup: accessGroup,
kSecValueData: password] as [String: Any]
let addStatus = SecItemAdd(attributes as CFDictionary, nil)
Use any of the groups to which your app belongs. If you try to use an access group to which your app doesn’t belong, the operation fails and returns the errSecMissingEntitlement status. This includes attempts to “prime” an entry using a zero-length string as the value for the kSecAttrAccessGroup key, because the empty string represents an invalid group.
必须使用应用属于的访问组.如果尝试使用一个访问组,但是应用并不属于该访问组.操作会失败并返回errSecMissingEntitlement结果码.为kSecAttrAccessGroup键设置一个空字符串也会得到该结果,因为空字符串是非法的访问组.
If you don’t specify any access group when adding an item, keychain services applies your app’s default access group, which is the first group named in the concatenated list of groups described in Set Your App’s Access Groups.
如果添加时不指定任何访问组,钥匙链服务默认将其添加到默认的访问组,该访问组是在 Set Your App’s Access Groups描述访问组列表中的第一个.
When you search for keychain items with the SecItemCopyMatching method, you can likewise specify an access group in the search query to limit your search to a particular access group:
当你用SecItemCopyMatching方法搜索项目时,你可以在搜索查询中指定访问组来实现在特定访问组中搜索:
let query = [kSecClass: kSecClassGenericPassword,
kSecAttrService: service,
kSecAttrAccount: username,
kSecReturnAttributes: true,
kSecAttrAccessGroup: accessGroup,
kSecReturnData: true] as [String: Any]
var item: CFTypeRef?
let readStatus = SecItemCopyMatching(query as CFDictionary, &item)
If you specify a group to which your app doesn’t belong, no items match and the query returns the errSecItemNotFound status. If you don’t specify an access group in the query, the search matches any of your app’s groups.
如果你指定了一个应用并不属于的访问组,不会有项目匹配并返回errSecItemNotFound状态码.如果在搜索查询中不指定访问组,会在所有的访问组中进行搜索.
3 See Also 参考
3.1 Keychain Item Access钥匙链项目访问
Keychain Access Groups Entitlement钥匙链访问组权限文件
The identifiers for the keychain groups that the app may share items with.
权限文件描述了应用之间能分享项目的访问组.
Key: keychain-access-groups
键:keychain-access-groupsRestricting Keychain Item Accessibility限制钥匙链项目可访问性
Set the conditions under which an app can access a keychain item such as a password.SecAccessControlCreateWithFlags
Creates a new access control object with the specified protection type and flags.SecAccessControlCreateFlags
Access control constants that dictate how a keychain item may be used.SecAccessControlRef
An opaque type that contains information about how a keychain item may be used.SecAccessControlGetTypeID
Returns the unique identifier of the opaque type to which a keychain item access control object belongs.