确保为应用程序读取 Yes
沙盒列:
检查应用二进制文件是否已沙盒化:
启动终端应用。
导航到应用程序 bin
目录。
发出此命令: codesign -dvvv --entitlements :- executable_path
(应用程序的路径在哪里 executable_path
):
调试沙盒应用
调试器通过 TCP 连接到 Xamarin.Mac 应用,这意味着在启用沙盒时,它无法连接到应用,因此,如果尝试在没有启用适当权限的情况下运行应用,则会收到错误“无法连接到调试器”。
允许传出网络连接(客户端)权限是调试器所需的权限,启用此权限将允许正常调试。 由于你不能在没有调试的情况下进行调试,因此我们已更新 CompileEntitlements
了目标,以便 msbuild
自动将该权限添加到仅针对调试生成沙盒的任何应用的权利。 发布版本应使用权利文件中指定的权利(未修改)。
解决应用沙盒冲突
如果沙盒 Xamarin.Mac 应用程序尝试访问未显式允许的资源,则会发生应用沙盒冲突。 例如,我们的 Web 视图不再能够显示 Apple 网站。
当 Visual Studio for Mac 中指定的权利设置不符合应用程序要求时,将发生最常见的应用沙盒冲突源。 同样,回到我们的示例,缺少的网络连接权利,使 Web 视图不起作用。
发现应用沙盒冲突
如果怀疑 Xamarin.Mac 应用程序中发生了应用沙盒冲突,则发现问题的最快方法是使用 控制台 应用。
请执行以下操作:
编译有问题的应用,并从 Visual Studio for Mac 运行它。
打开 控制台 应用程序(发件人 /Applications/Utilties/
)。
在边栏中选择 “所有邮件 ”,然后在搜索中输入 sandbox
:
对于上面的示例应用,可以看到 Kernal 由于应用沙盒而阻止 network-outbound
了流量,因为我们没有请求该权限。
使用权利修复应用沙盒冲突
现在,我们已经了解如何查找应用沙盒冲突,让我们看看如何通过调整应用程序的权利来解决这些冲突。
请执行以下操作:
在 Solution Pad 中,双击 Entitlements.plist 文件将其打开以供编辑。
在“权利”部分下,检查“允许传出网络”连接(客户端)检查框:
保存对应用程序的更改。
如果我们对示例应用执行上述操作,然后生成并运行它,则 Web 内容现在将显示为预期。
深入应用沙盒
应用沙盒提供的访问控制机制很少且易于理解。 但是,每个应用将采用应用沙盒的方式是唯一的,并基于应用的要求。
为保护 Xamarin.Mac 应用程序免受恶意代码的攻击,应用(或它使用的库或框架之一)中只需要一个漏洞,才能控制应用与系统的交互。
应用沙盒旨在通过允许你指定应用程序与系统的预期交互来防止接管(或限制它可能导致的损害)。 系统只会授予对应用程序完成其作业所需的资源的访问权限,且无需执行任何操作。
在针对应用沙盒进行设计时,你要针对最坏的情况进行设计。 如果应用程序确实受到恶意代码的入侵,则只能访问应用沙盒中的文件和资源。
权利和系统资源访问
如上所述,未沙盒的 Xamarin.Mac 应用程序被授予运行应用的用户的完全权限和访问权限。 如果受到恶意代码的入侵,则非受保护的应用可以充当恶意行为的代理,并有可能造成伤害。
通过启用应用沙盒,可以删除除一组最少的权限,然后使用 Xamarin.Mac 应用的权利按需重新启用这些权限。
通过编辑其 Entitlements.plist 文件并检查或从编辑器下拉列表中选择所需的权限来修改应用程序的应用沙盒资源:
容器目录和文件系统访问
当 Xamarin.Mac 应用程序采用应用沙盒时,它有权访问以下位置:
应用容器目录 - 首次运行时,OS 会创建一个特殊的 容器目录,其中所有资源都位于其中,只有该目录可以访问该目录 。 该应用将对此目录具有完全读/写访问权限。
应用组容器目录 - 可以向应用授予对同一组中应用之间共享的一个或多个 组容器 的访问权限。
用户指定的文件 - 应用程序会自动获取对用户显式打开或拖放到应用程序上的文件的访问权限。
相关项 - 使用适当的权利,应用程序可以访问具有相同名称但扩展名不同的文件。 例如,已保存为 .txt
文件和文件 .pdf
的文档。
临时目录、命令行工具目录和特定的世界可读位置 - 你的应用对系统指定的其他定义位置中的文件具有不同程度的访问权限。
应用容器目录
Xamarin.Mac 应用程序的应用容器目录具有以下特征:
它位于用户主目录(通常 ~Library/Containers
)中的隐藏位置,可通过应用程序中的函数(如下所示)进行访问 NSHomeDirectory
。 由于它位于“主页”目录中,因此每个用户都将为应用获取自己的容器。
应用对容器目录及其所有子目录及其内部文件具有无限制的读/写访问权限。
大多数 macOS 的路径查找 API 都与应用的容器相关。 例如,容器将有自己的 库 (通过 NSLibraryDirectory
)、 应用程序支持 和 首选项 子目录进行访问。
macOS 通过代码签名建立并强制实施应用与其容器之间的连接。 即使是另一个应用也尝试使用其 捆绑标识符欺骗应用,但由于代码签名,它将无法访问容器。
容器不适用于用户生成的文件。 而是适用于应用程序使用的文件,例如数据库、缓存或其他特定类型的数据。
对于 鞋盒 类型的应用(如 Apple 的照片应用),用户的内容将进入容器。
遗憾的是,Xamarin.Mac 还没有 100% 的 API 覆盖率(与 Xamarin.iOS 不同),因此 NSHomeDirectory
API 尚未在当前版本的 Xamarin.Mac 中映射。
作为临时解决方法,可以使用以下代码:
[System.Runtime.InteropServices.DllImport("/System/Library/Frameworks/Foundation.framework/Foundation")]
public static extern IntPtr NSHomeDirectory();
public static string ContainerDirectory {
get {
return ((NSString)ObjCRuntime.Runtime.GetNSObject(NSHomeDirectory())).ToString ();
应用组容器目录
从 Mac macOS 10.7.5(及更高)开始,应用程序可以使用 com.apple.security.application-groups
权利访问组中所有应用程序通用的共享容器。 可以将此共享容器用于面向非用户的内容,例如数据库或其他类型的支持文件(如缓存)。
组容器会自动添加到每个应用的沙盒容器(如果它们是组的一部分),并存储在 ~/Library/Group Containers/<application-group-id>
其中。 组 ID 必须 以开发团队 ID 和句点开头,例如:
<team-id>.com.company.<group-name>
有关详细信息,请参阅 Apple 在权利密钥参考中向应用程序组添加应用程序。
应用容器外部的 Powerbox 和文件系统访问
沙盒 Xamarin.Mac 应用程序可以通过以下方式访问其容器外部的文件系统位置:
在用户的特定方向(通过打开和保存对话框或其他方法(如拖放) 。
通过使用特定文件系统位置(如 /bin
或) /usr/lib
的权利。
当文件系统位置位于世界可读(如共享)的某些目录中时。
Powerbox 是与用户交互以扩展沙盒 Xamarin.Mac 应用的文件访问权限的 macOS 安全技术。 Powerbox 没有 API,但在应用调用或NSOpenPanel
NSSavePanel
应用时以透明方式激活。 Powerbox 访问是通过为 Xamarin.Mac 应用程序设置的权利启用的。
当沙盒应用显示“打开”或“保存”对话框时,该窗口由 Powerbox(而不是 AppKit)显示,因此有权访问用户有权访问的任何文件或目录。
当用户从“打开”或“保存”对话框中选择文件或目录(或拖动到应用图标上)时,Powerbox 会将关联的路径添加到应用的沙盒。
此外,系统会自动将以下内容允许沙盒应用:
连接系统输入法。
从“服务”菜单中调用用户选择的服务(仅适用于服务提供商标记为沙盒应用安全的服务)。
从“打开最近打开”菜单中选择“打开文件”。
在其他应用程序之间使用复制和粘贴。
从以下可读位置读取文件:
/sbin
/usr/bin
/usr/lib
/usr/sbin
/usr/share
/System
- 读取和写入由 .
NSTemporaryDirectory
创建的目录中的文件。
默认情况下,沙盒 Xamarin.Mac 应用打开或保存的文件将保持可访问状态,直到应用终止(除非应用退出时文件仍处于打开状态)。 下次启动应用时,打开的文件将通过 macOS 恢复功能自动还原到应用的沙盒。
若要为位于 Xamarin.Mac 应用容器外部的文件提供持久性,请使用安全范围的书签(请参阅下文)。
应用沙盒允许应用访问具有相同文件名但不同扩展名的相关项。 此功能有两个部分:a) 应用 Info.plst
文件中相关扩展的列表,b) 代码告知沙盒应用将对这些文件执行的操作。
在以下两种情况下,这很有意义:
- 应用需要能够保存文件的不同版本(具有新的扩展名)。 例如,将
.txt
文件导出到 .pdf
文件。 若要处理这种情况,必须使用 a NSFileCoordinator
访问文件。 首先调用 WillMove(fromURL, toURL)
该方法,将文件移动到新的扩展名,然后调用 ItemMoved(fromURL, toURL)
。
- 该应用需要打开一个扩展名为一个的主文件,以及多个具有不同扩展名的支持文件。 例如,电影和字幕文件。 使用 a
NSFilePresenter
获取对辅助文件的访问权限。 向属性提供主文件 PrimaryPresentedItemURL
,并将辅助文件提供给 PresentedItemURL
该属性。 打开主文件时,调用 AddFilePresenter
类的方法 NSFileCoordinator
注册辅助文件。
在这两种情况下,应用的 Info.plist 文件必须声明应用可以打开的文档类型。 对于任何文件类型,请将 NSIsRelatedItemType
YES> 值添加到数组中的 CFBundleDocumentTypes
条目。
使用沙盒应用打开和保存对话框行为
从沙盒 Xamarin.Mac 应用调用这些限制时,将对其施加NSOpenPanel
NSSavePanel
以下限制:
- 不能以编程方式调用 “确定 ”按钮。
- 不能以编程方式更改用户的选择
NSOpenSavePanelDelegate
。
此外,以下继承修改已到位:
- 非沙盒应用 -
NSOpenPanel
NSSavePanel``NSPanel``NSWindow``NSResponder``NSObject``NSOpenPanel``NSSavePanel``NSObject``NSOpenPanel``NSSavePanel
安全范围的书签和持久性资源访问
如上所述,沙盒 Xamarin.Mac 应用程序可以通过直接用户交互(由 PowerBox 提供)访问容器外部的文件或资源。 但是,在应用启动或系统重启时,对这些资源的访问不会自动保留。
通过使用 安全范围的书签,沙盒 Xamarin.Mac 应用程序可以保留用户意向,并在应用重启后保留对给定资源的访问权限。
安全范围的书签类型
使用安全范围的书签和持久资源访问时,有两个 sistine 用例:
应用范围的书签提供对用户指定的文件或文件夹的持久访问。
例如,如果沙盒 Xamarin.Mac 应用程序允许使用打开外部文档进行编辑(使用), NSOpenPanel
应用可以创建应用范围的书签,以便将来再次访问同一文件。
文档范围的书签提供对子文件的特定文档持久访问。
例如,一个视频编辑应用,用于创建一个项目文件,该文件有权访问单个图像、视频剪辑和声音文件,稍后将合并为单个电影。
当用户(通过 a) NSOpenPanel
将资源文件导入项目时,应用会为项目中存储的项创建文档范围的书签,以便该文件始终可供应用访问。
任何可以打开书签数据和文档本身的应用程序都可以解析文档范围的书签。 这支持可移植性,允许用户将项目文件发送给其他用户,并让所有书签也适用于它们。
文档范围的书签只能指向单个文件,而不能指向文件夹,并且该文件不能位于系统使用的位置(例如/private
或/Library
)。
使用安全范围的书签
使用任一类型的安全作用域书签需要执行以下步骤:
- 在需要使用安全作用域书签的 Xamarin.Mac 应用中设置适当的权利 - 对于应用范围的书签 ,请将
com.apple.security.files.bookmarks.app-scope
权利密钥设置为 true
。 对于文档范围的书签,请将 com.apple.security.files.bookmarks.document-scope
权利键设置为 true
。
- 创建安全范围的书签 - 为此,用户提供访问权限的任何文件或文件夹(例如,通过
NSOpenPanel
),应用将需要永久访问权限。 public virtual NSData CreateBookmarkData (NSUrlBookmarkCreationOptions options, string[] resourceValues, NSUrl relativeUrl, out NSError error)
使用类的方法NSUrl
创建书签。
- 解析安全作用域书签 - 当应用需要再次访问资源时(例如重启后),需要将书签解析为安全范围的 URL。
public static NSUrl FromBookmarkData (NSData data, NSUrlBookmarkResolutionOptions options, NSUrl relativeToUrl, out bool isStale, out NSError error)
使用类的方法NSUrl
解析书签。
- 显式通知系统要从安全作用域 URL 访问文件 - 在获取上述安全作用域 URL 后需要立即执行此步骤,或者以后在放弃对资源的访问权限后重新获得对资源的访问权限时,需要立即完成此步骤。
StartAccessingSecurityScopedResource ()
调用类的方法NSUrl
以开始访问安全范围的 URL。
- 显式通知系统你已完成从安全范围的 URL 访问文件 - 尽快,当应用不再需要访问该文件时,你应该通知系统(例如,如果用户关闭它)。
StopAccessingSecurityScopedResource ()
调用类的方法NSUrl
以停止访问安全范围的 URL。
放弃对资源的访问权限后,需要再次返回到步骤 4 以重新建立访问权限。 如果重启 Xamarin.Mac 应用,则必须返回到步骤 3 并重新解析书签。
未能释放对安全范围的 URL 资源的访问权限将导致 Xamarin.Mac 应用泄漏内核资源。 因此,在重新启动文件系统位置之前,应用将无法再将其添加到其容器中。
应用沙盒和代码签名
启用应用沙盒并启用 Xamarin.Mac 应用(通过权利)的特定要求后,必须对项目进行代码签名,使沙盒生效。 必须执行代码签名,因为应用沙盒所需的权利链接到应用的签名。
macOS 强制应用容器与其代码签名之间的链接,这样任何其他应用程序都无法访问该容器,即使它欺骗了应用捆绑 ID 也是如此。 此机制的工作原理如下:
- 当系统创建应用的容器时,它会在该容器上设置访问控制列表(ACL)。 列表中的初始访问控制项包含应用的 指定要求(DR),该要求 描述了如何识别应用的未来版本(升级后)。
- 每次启动具有相同捆绑 ID 的应用时,系统都会检查应用的代码签名与容器 ACL 中某个条目中指定的指定要求匹配。 如果系统找不到匹配项,它将阻止应用启动。
代码签名的工作原理如下:
- 在创建 Xamarin.Mac 项目之前,请从 Apple 开发人员门户获取开发证书、分发证书和开发人员 ID 证书。
- 当 Mac App Store 分发 Xamarin.Mac 应用时,它使用 Apple 代码签名进行签名。
测试和调试时,将使用已签名的 Xamarin.Mac 应用程序版本(将用于创建应用容器)。 稍后,如果想要从 Apple App Store 测试或安装版本,它将使用 Apple 签名进行签名,并且无法启动(因为它没有与原始应用容器相同的代码签名)。 在这种情况下,你将获得类似于以下内容的崩溃报告:
Exception Type: EXC_BAD_INSTRUCTION (SIGILL)
若要解决此问题,需要调整 ACL 入口以指向 Apple 签名版本的应用。
有关创建和下载沙盒所需的预配配置文件的详细信息,请参阅上面的“ 签名和预配应用 ”部分。
调整 ACL 条目
若要允许 Apple 签名版本的 Xamarin.Mac 应用运行,请执行以下操作:
- 打开终端应用(in
/Applications/Utilities
)。
- 打开 Xamarin.Mac 应用的 Apple 签名版本的 Finder 窗口。
- 在终端窗口中键入
asctl container acl add -file
。
- 从 Finder 窗口拖动 Xamarin.Mac 应用的图标,并将其拖放到终端窗口中。
- 文件的完整路径将添加到终端中的命令。
- 按 Enter 执行该命令。
容器的 ACL 现在包含 Xamarin.Mac 应用和 macOS 这两个版本的指定代码要求,现在允许任一版本运行。
显示 ACL 代码要求的列表
可以通过执行以下操作来查看容器 ACL 中的代码要求列表:
- 打开终端应用(in
/Applications/Utilities
)。
- 键入
asctl container acl list -bundle <container-name>
。
- 按 Enter 执行该命令。
通常是 <container-name>
Xamarin.Mac 应用程序的捆绑标识符。
为应用沙盒设计 Xamarin.Mac 应用
为应用沙盒设计 Xamarin.Mac 应用时,应遵循一个常见的工作流。 也就是说,在应用中实现沙盒的具体细节对于给定应用的功能是独一无二的。
采用应用沙盒的六个步骤
为应用沙盒设计 Xamarin.Mac 应用通常包括以下步骤:
- 确定应用是否适合沙盒。
- 设计开发和分发策略。
- 解决任何 API 不兼容问题。
- 将所需的应用沙盒权利应用于 Xamarin.Mac 项目。
- 使用 XPC 添加特权分离。
- 实施迁移策略。
你不仅必须在应用捆绑包中对主要可执行文件进行沙盒,而且必须沙盒包含每个帮助程序应用或该工具。 这是从 Mac App Store 分发的任何应用所必需的,如果可能,应针对任何其他形式的应用分发完成此操作。
有关 Xamarin.Mac 应用捆绑包中所有可执行二进制文件的列表,请在终端中键入以下命令:
find -H [Your-App-Bundle].app -print0 | xargs -0 file | grep "Mach-O .*executable"
应用程序的捆绑包的名称和路径在哪里 [Your-App-Bundle]
。
确定 Xamarin.Mac 应用是否适合沙盒
大多数 Xamarin.Mac 应用与应用沙盒完全兼容,因此适合沙盒。 如果应用需要应用沙盒不允许的行为,则应考虑一种替代方法。
如果应用需要以下行为之一,则它与应用沙盒不兼容:
- 授权服务 - 使用应用沙盒时,不能使用 Authorization Services C 参考中所述的功能。
- 辅助功能 API - 不能沙盒辅助应用,例如屏幕阅读器或控制其他应用程序的应用。
- 将 Apple 事件发送到任意应用 - 如果应用需要将 Apple 事件发送到未知的任意应用,则无法将其沙盒化。 对于已知的已调用应用列表,该应用仍可以沙盒化,权利需要包含调用的应用列表。
- 将分布式通知中的用户信息字典发送到其他任务 - 使用应用沙盒,在发布到
NSDistributedNotificationCenter
对象以传送其他任务时,不能包含userInfo
字典。
- 加载内核扩展 - 应用沙盒禁止加载内核扩展。
- 应用沙盒禁止在“打开”和“保存”对话框中 模拟用户输入 - 以编程方式操作“打开”或“保存”对话框以模拟或更改用户输入。
- 在其他应用 上访问或设置首选项 - 应用沙盒禁止操作其他应用的设置。
- 配置网络设置 - 应用沙盒禁止操作网络设置。
- 终止其他应用 - 应用沙盒禁止使用
NSRunningApplication
终止其他应用。
解决 API 不兼容问题
为应用沙盒设计 Xamarin.Mac 应用时,可能会遇到与某些 macOS API 的用法不兼容的情况。
下面是一些常见问题和可解决这些问题的事项:
- 打开、保存和跟踪文档 - 如果使用其他
NSDocument
任何技术管理文档,则应由于对应用沙盒的内置支持而切换到文档。 NSDocument
如果用户在 Finder 中移动文档,则自动使用 PowerBox,并支持将文档保留在沙盒中。
- 保留对文件系统资源的 访问 - 如果 Xamarin.Mac 应用依赖于对其容器外部资源的持久访问,请使用安全范围的书签来维护访问权限。
- 为应用创建登录项 - 使用应用 沙盒时,不能使用
LSSharedFileList
创建登录项,也不能使用 LSRegisterURL
操作启动服务的状态。 SMLoginItemSetEnabled
使用 Apples 使用 Service Management Framework 文档添加登录项中所述的函数。
- 访问用户数据 - 如果使用 POSIX 函数(例如
getpwuid
从目录服务获取用户的主目录),请考虑使用 Cocoa 或 Core Foundation 符号,例如 NSHomeDirectory
。
- 访问其他应用的 首选项 - 由于应用沙盒将查找路径 API 定向到应用的容器,因此修改首选项发生在该容器中,并且不允许访问其他应用首选项。
- 在 Web 视图中 使用 HTML5 嵌入式视频 - 如果 Xamarin.Mac 应用使用 WebKit 播放嵌入式 HTML5 视频,则还必须将应用链接到 AV Foundation 框架。 应用沙盒将阻止 CoreMedia 播放这些视频,否则。
应用所需的应用沙盒权利
需要编辑要在应用沙盒中运行的任何 Xamarin.Mac 应用程序的权利,并检查“启用应用沙盒”检查框。
根据应用的功能,可能需要启用其他权利才能访问 OS 功能或资源。 将请求的权利降到运行应用所需的最低要求时,应用沙盒效果最佳,因此只需随机启用权利即可。
若要确定 Xamarin.Mac 应用所需的权利,请执行以下操作:
- 启用应用沙盒并运行 Xamarin.Mac 应用。
- 运行应用的功能。
- 打开控制台应用(可用
/Applications/Utilities
),并在“所有消息”日志中查找sandboxd
冲突。
- 对于每个
sandboxd
冲突,请通过使用应用容器而不是其他文件系统位置来解决该问题,或者应用应用沙盒权利来启用对受限 OS 功能的访问权限。
- 重新运行并再次测试所有 Xamarin.Mac 应用功能。
- 重复,直到解决所有
sandboxd
冲突。
使用 XPC 添加特权分离
为应用沙盒开发 Xamarin.Mac 应用时,请查看应用在特权和访问权限方面的行为,然后考虑将高风险操作分成自己的 XPC 服务。
有关详细信息,请参阅 Apple 的“创建 XPC 服务和守护程序和服务编程指南”。
实施迁移策略
如果要发布以前未沙盒的 Xamarin.Mac 应用程序的新沙盒版本,则需要确保当前用户具有流畅的升级路径。
有关如何实现容器迁移清单的详细信息,请阅读 Apple 将 应用迁移到沙盒 文档。
本文详细介绍了 Xamarin.Mac 应用程序的沙盒。 首先,我们创建了一个简单的 Xamarin.Mac 应用来显示应用沙盒的基础知识。 接下来,我们介绍了如何解决沙盒冲突。 然后,我们深入探讨了应用沙盒,最后,我们研究了为应用沙盒设计 Xamarin.Mac 应用。
- 发布到 App Store
- 关于应用沙盒
- 常见应用沙盒问题