gpt4 book ai didi

macos - 如何允许所有应用程序在没有提示的情况下访问钥匙串(keychain)项

转载 作者:行者123 更新时间:2023-12-04 12:52:08 25 4
gpt4 key购买 nike

Keychain Access 中有一个选项允许所有应用程序不受限制地访问钥匙串(keychain)项目。
Keychain Access - Access Control tab

我不知道如何以编程方式设置它。我尝试使用空 ACL 创建和设置新的 SecAccessRef,并没有真正改变任何东西(使用 SecItemUpdate 更新 kSecAttrAccess )。我还尝试获取项目的所有授权标签的所有 ACL 列表,并将 ACL 内容设置为该 ACL/标签组合的空数组。我能够清除允许的应用程序列表,但这并不允许所有应用程序不受限制地访问项目。我看不到使用钥匙串(keychain) api 设置它的方法。

所以我的问题是如何操作访问对象或其 ACL 以允许不受限制地访问钥匙串(keychain)项或至少不受限制地读取?

最佳答案

正如@mike-c 在他的回答中所说,似乎无法使用最初为支持 iOS 和 iCloud 而引入的较新的 Keychain API 来实现该解决方案。尤其是访问控制 API 不再兼容 macOS 用来处理它的原始方式。在此之上还引入了大量不同的 API,如 session 711 from WWDC 2014: Keychain and Authentication with Touch ID 所示。 (从 09:40 开始),这使得理解更加困难。

@mike-c 的答案包含许多提示,但没有显示完整的图片。类似于 this question在 Apple Developer Forums 上,它告诉必须在创建时为 Keychain 项目设置适当的访问控制。有点遗憾的是,新文档中不再提及旧的 Keychain API,因此我不得不深入研究 Keychain Services Programming Guide 的存档版本。 .

创建访问对象

为了描述访问配置,我们必须使用具有关联访问控制列表(SecAccess)的所谓访问对象(SecACL)。要了解有关 ACL 的更多信息,请参阅 old 中的说明。或 new (and less detailed)文档的版本。出于此答案的目的,ACL 定义了哪个应用程序可以访问给定操作的 Keychain 项。

使用 SecAccessCreate(…)您可以使用基于提供的参数的预定义系统默认配置创建新的访问对象。默认情况下,它包含三个 ACL。我尝试按照@mike-c 的答案中的建议添加一个新的 ACL,但遇到了一种奇怪的行为,有时会授予对项目的访问权,有时则不会。

this documentation page 的“高级主题”部分描述了成功的方法。 .基本上,我们不是添加新的 ACL,而是修改现有的 ACL 之一。

此函数创建一个为所有应用程序配置了无限制访问权限的访问对象。它是用 Swift 编写的,保持了 Keychain C API 的风格。这很尴尬,但这次一致性赢了。

/// Creates an access object with the system default configuration which has an altered ACL
/// to allow access for all applications.
///
/// - Parameter descriptor: The name of the item as it should appear in security dialogs.
/// - Parameter accessRef: The pointer to the new access object.
/// - Returns: A result code.
func SecAccessCreateForAllApplications(
descriptor: CFString,
accessRef outerAccessRef: UnsafeMutablePointer<SecAccess?>
) -> OSStatus {
var accessRef: SecAccess?

// Create an access object with access granted to no application (2nd parameter).
// It comes configured with 3 default ACLs.
let accessCreateStatus = SecAccessCreate(
descriptor,
[] as CFArray, // No application has access
&accessRef
)

guard accessCreateStatus == errSecSuccess else { return accessCreateStatus }
guard let access = accessRef else { return accessCreateStatus }

// Extract the default ACLs from the created access object for the *decrypt* authorization tag.
guard let aclList = SecAccessCopyMatchingACLList(
access,
kSecACLAuthorizationDecrypt
) as? [SecACL] else { return errSecInvalidACL }

// There should be exactly one ACL for the *decrypt* authorization tag.
guard aclList.count == 1 else { return errSecInvalidACL }
guard let decryptACL = aclList.first else { return errSecInvalidACL }

// Extract all authorizations from the default ACL for the *decrypt* authorization tag.
let allAuthorizations = SecACLCopyAuthorizations(decryptACL)

// Remove the default ACL for the *decrypt* authorization tag from the access object.
let aclRemoveStatus = SecACLRemove(decryptACL)

guard aclRemoveStatus == errSecSuccess else { return aclRemoveStatus }

// Create a new ACL with access for all applications and add it to the access object.
var newDecryptACLRef: SecACL?
let aclCreateStatus = SecACLCreateWithSimpleContents(
access,
nil, // All applications have access
descriptor,
[], // Empty prompt selector
&newDecryptACLRef
)

guard aclCreateStatus == errSecSuccess else { return aclCreateStatus }
guard let newDecryptACL = newDecryptACLRef else { return aclCreateStatus }

// Set the authorizations extracted from the default ACL to the newly created ACL.
let aclUpdateAuthorizationStatus = SecACLUpdateAuthorizations(newDecryptACL, allAuthorizations)

guard aclUpdateAuthorizationStatus == errSecSuccess else { return aclUpdateAuthorizationStatus }

// Finally, write the access to the outer pointer.
outerAccessRef.initialize(to: access)

return errSecSuccess
}

编写钥匙串(keychain)项目

第二部分相当简单。事实证明,您可以在使用 SecItemAdd(…) 创建钥匙串(keychain)项时指定访问对象。 .将自定义访问对象作为键值 kSecAttrAccess到属性字典中,它将被应用。

此代码使用配置的自定义访问对象写入 Keychain 项:

var accessRef: SecAccess?

let accessCreateStatus = SecAccessCreateForAllApplications(
descriptor: "" as CFString, // Actually not necessary
accessRef: &accessRef
)

guard accessCreateStatus == errSecSuccess else { exit(EXIT_FAILURE) }
guard let access = accessRef else { exit(EXIT_FAILURE) }

let attributes: [CFString: Any] = [
kSecClass: kSecClassGenericPassword,
kSecAttrAccount: "Foo",
kSecValueData: "bar".data(using: .utf8)!,
kSecAttrAccess: access
]

let itemAddStatus = SecItemAdd(attributes as CFDictionary, nil)

guard itemAddStatus == errSecSuccess else { exit(EXIT_FAILURE) }

阅读钥匙串(keychain)项目

在 Keychain Access 应用程序中显示 Keychain 项时,它被正确标记为可供所有应用程序访问。

您可以在不显示任何对话框的情况下从另一个应用程序读取项目。以下是读取和解密项目有效负载的代码:

let attributes: [CFString: Any] = [
kSecClass: kSecClassGenericPassword,
kSecAttrAccount: "Foo",
kSecReturnData: kCFBooleanTrue as Any,
kSecMatchLimit: kSecMatchLimitOne
]

var dataRef: AnyObject?
let status = SecItemCopyMatching(attributes as CFDictionary, &dataRef)

guard status == errSecSuccess else { exit(EXIT_FAILURE) }
guard let data = dataRef as? Data else { exit(EXIT_FAILURE) }
guard let string = String(data: data, encoding: .utf8) else { exit(EXIT_FAILURE) }

print(string) // => bar

我还没有掌握旧的 Keychain API,因此欢迎对所介绍的方法提供任何反馈。

关于macos - 如何允许所有应用程序在没有提示的情况下访问钥匙串(keychain)项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41832893/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com