Mac 开发(一) 苹果沙盒机制sandbox 简介
文章目录
- Mac 开发(一) 苹果沙盒机制sandbox简介
- 1 Mac sandbox简介
- 1.1 关于应用程序沙盒
- 1.2 为啥要用沙盒机制
- 2 沙盒原理
- 3 xcode中开启沙盒权限
- 3.1 XCode Capabilities 开启Sandbox权限
- 3.1.1 Capabilities 开启Sandbox权限
- 3.1.2 Entitlements 直接变xml,开启Sandbox权限
- 3.2 Mac 文件沙盒化实战
- 3.2.1 没有使用sandbox使可以任意访问文件
- 3.2.2 Sandbox下访问文件的坑点
Mac 开发(一) 苹果沙盒机制sandbox简介
mac沙盒实战demo点击这里下载:【MacFileAccessInSandbox】
1 Mac sandbox简介
1.1 关于应用程序沙盒
- 什么是沙盒?
维基百科的解释:
- 在计算机安全领域,沙盒(英语:sandbox,又译为沙箱)是一种安全机制,为运行中的程序提供的隔离环境。通常是作为一些来源不可信、具破坏力或无法判定程序意图的程序提供实验之用
- 沙盒通常严格控制其中的程序所能访问的资源,比如,沙盒可以提供用后即回收的磁盘及内存空间。在沙盒中,网络访问、对真实系统的访问、对输入设备的读取通常被禁止或是严格限制。从这个角度来说,沙盒属于虚拟化的一种。
- 沙盒中的所有改动对操作系统不会造成任何损失。通常,这种技术被计算机技术人员广泛用于测试可能带毒的程序或是其他的恶意代码
在OS X以及IOS系统中限制了进程对一些资源的访问权限,例如网络、某些特殊路径、文件的读写等等,限定了进程的一些行为,从而保证进程不会做出超越权限的操作。
下面看看苹果对沙盒的解释:
应用沙箱是macOS提供的一种访问控制技术,在内核级别执行。如果应用程序受到威胁,它的目的是防止系统和用户数据受到损害。通过Mac应用商店发布的应用必须采用应用沙箱。通过开发者ID在Mac应用商店外签名和分发的应用程序也可以(在大多数情况下应该)使用应用沙箱。
Mac OSX自从10.6系统开始引入沙盒机制,规定发布到Mac AppStore的应用,必须遵守沙盒约定。沙盒对应用访问的系统资源,硬件外设,文件,网络,XPC,都做了严格的限制,这样能防止恶意的App通过系统漏洞,攻击系统,获取控制权限,保证了OSX系统的安全。
沙盒相当于给每个App一个独立的空间,你只能在自己的小天地里面玩。要获取自己空间之外的资源必须获得授权。
那么苹果为啥要限制提交Appstore的app必须使用苹果的沙盒机制呢?
1.2 为啥要用沙盒机制
复杂的系统总是会有漏洞,而软件的复杂性只会随着时间的推移而增加。无论您多么小心地采用安全编码实践并防范bug,攻击者只需要通过一次防御就可以成功。虽然应用沙箱不能阻止对您的应用程序的攻击,但它可以最小化一个成功的攻击所造成的伤害。
非沙箱应用程序拥有运行该应用程序的用户的全部权限,并可以访问用户可以访问的任何资源。如果该应用程序或与之链接的任何框架包含安全漏洞,攻击者可能会利用这些漏洞来控制该应用程序,这样,攻击者就可以做用户可以做的任何事情。
为了缓解这个问题,应用沙箱策略有两个方面:
- 应用沙箱允许你描述你的应用如何与系统交互。然后,系统授予应用程序完成工作所需的访问权限,仅此而已。
- 通过打开和保存对话框、拖放和其他熟悉的用户交互,应用沙箱允许用户透明地授予应用额外的访问权限。
2 沙盒原理
- 沙盒的大致工作流程入下图所示:
1
进程尝试进行一次系统调用(system call),调用内核功能。2、3
MAC层需要根据该进程的安全策略判断此次系统调用是否可以执行。4、5、6、7、8、9
如果存在策略的话,通过sandbox.kext(hook函数)和AppleMatch.kext(沙盒的profile解析)两个内核扩展实现权限的检查。10
返回调用结果
与沙盒系统相关的模块大致如下:
.libSystem.dylib
: 提供sandbox_init
、sandbox_free_error
等函数。libSandbox.dylib
: 提供解析,编译,生成*.sb
的沙盒profile
的函数。sandbox.kext
:提供了system call
的hook
函数AppleMatch.kext
:提供了解析profile
的函数
- 结构图大致如下:
- 沙盒的工作流程大致可以总结为:
- 通过
sandbox_init
初始化某沙盒策略脚本并编译为二进制文件- 在进程进行
system call
时,通过TrustedBSD
提供的hook
模块,利用Sandbox.kext
提供的system call hook
函数,结合沙盒策略进行判断,该进程是否有权限执行该system call
。
3 xcode中开启沙盒权限
3.1 XCode Capabilities 开启Sandbox权限
3.1.1 Capabilities 开启Sandbox权限
应用开发完成提交到App Store时,必须进行沙盒化。切换到工程target设置Tab的Capabilities中。
- 第一项就是App Sandbox开关,点击ON,表示应用使用沙盒。
上图的选项的一些解释如下:
- Network:网络访问控制
Incoming Connections (Server)
: 应用做为Server对外提供HTTP,FTP等服务时需要打开。如果你的App担任服务器角色,需要连接通信需要开启此权限。Outgoing Connections (Client)
: 做为客户端,访问服务器时需要打开。如果你的App需要作为客户端进行socket连接通信需要开启此权限。
- Hardware:硬件资源控
它包含下面这些子项:
Camera
: 如果你需要开启摄像头功能,勾选此项。Audio Input
: 如果你需要获取音频 输入权限(如麦克风),勾选此项。USB
: 如果你需要使用USB传输文件,需要开启此功能
4:Printing
: 如果你需要打印文件里面的内容,需要开启此功能
- App Data:获取系统的联系人,位置,日历服务时需要打开
Contacts
: 如果要访问联系人,需要勾选此项Location
: 如果需要定位,需要勾选此项。Calendar
: 如果需要访问日历,需要勾选此项。
- File Access:文件和用户目录的访问控制,分为禁止
none
,只读,读写3类
User Selected File
:文档类应用或者需要用户选择打开某个文件时,需要选择合适的访问权限.Downloads Folder
: 如果需要访问当前用户 Downloads文件夹,需要勾选此项,可以设置为只读,或者可读可写Pictures Folder
: 如果需要访问当前用户 Pictures文件夹,需要勾选此项,可以设置为只读,或者可读可写Music Folder
: 如果需要访问当前用户 Music文件夹,需要勾选此项,可以设置为只读,或者可读可写Movies Folder
: 如果需要访问当前用户 Movies文件夹,需要勾选此项,可以设置为只读,或者可读可写
特别注意:如果应用中不需要的权限项,一律不要打开。否则App Review团队会拒绝你的应用上架.
3.1.2 Entitlements 直接变xml,开启Sandbox权限
实际上,在沙盒中每个需要访问权限的项都对应一个key,对应的value,YES 或 NO表示是否允许访问。当你选择了项后,都会记录在一个扩展名为.entitlements的plist 的文件中,如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict><key>com.apple.security.app-sandbox</key><true/><key>com.apple.security.assets.movies.read-write</key><true/><key>com.apple.security.assets.music.read-only</key><true/><key>com.apple.security.assets.pictures.read-only</key><true/><key>com.apple.security.cs.allow-dyld-environment-variables</key><true/><key>com.apple.security.cs.allow-jit</key><true/><key>com.apple.security.cs.allow-unsigned-executable-memory</key><true/><key>com.apple.security.cs.disable-executable-page-protection</key><true/><key>com.apple.security.cs.disable-library-validation</key><true/><key>com.apple.security.device.audio-input</key><true/><key>com.apple.security.device.camera</key><true/><key>com.apple.security.device.usb</key><true/><key>com.apple.security.files.bookmarks.app-scope</key><true/><key>com.apple.security.files.downloads.read-write</key><true/><key>com.apple.security.files.user-selected.read-write</key><true/><key>com.apple.security.network.client</key><true/><key>com.apple.security.network.server</key><true/><key>com.apple.security.personal-information.photos-library</key><true/><key>com.apple.security.print</key><true/><key>com.apple.security.temporary-exception.apple-events</key><array><string>com.apple.itunes</string></array><key>com.apple.security.temporary-exception.files.absolute-path.read-write</key><true/><key>com.apple.security.temporary-exception.shared-preference.read-only</key><array><string>com.apple.iphoto</string><string>com.apple.photobooth</string><string>com.apple.photos</string></array>
</dict>
</plist>
用plist属性显示如下:
应用打包时会对这个文件进行签名。
当应用运行期间要获取某个权限时,系统都会通过.entitlements
去检查应用是否有授权,如果没有就拒绝访问。
3.2 Mac 文件沙盒化实战
3.2.1 没有使用sandbox使可以任意访问文件
mac沙盒实战demo点击这里下载:【MacFileAccessInSandbox】
首先我们创建一个Mac app工程,我这里选择的是Swift版本的工程。
添加一些调用api的UI控件
连接绑定UI事件
实现一个简单的打开文件功能如下:
extension ViewController {fileprivate func openFile() {let openPanel = NSOpenPanel()openPanel.prompt = "Open"openPanel.allowsMultipleSelection = trueopenPanel.canChooseDirectories = trueopenPanel.canChooseFiles = trueopenPanel.resolvesAliases = trueopenPanel.nameFieldLabel = "Open File"openPanel.title = "Open"openPanel.allowedFileTypes = ["txt"]openPanel.begin { (response) inif response == .OK {let urls = openPanel.urlsfor url in urls {UserDefaults.standard.set(url, forKey: LastSaveFilePathKey)UserDefaults.standard.synchronize()self.filePathField.stringValue = url.pathlet text = try? String(contentsOf: url, encoding: .utf8 )self.textV.string = text ?? ""}}}}
}
- 接下来我们实现保存文件功能
/// 保存文件fileprivate func saveFile() {guard let lastSelectUrl = UserDefaults.standard.value(forKey: LastSaveFilePathKey) as? URL else {return}let text = textV.stringtry? text.write(to: lastSelectUrl, atomically: true, encoding: .utf8)}
接下来我们验证一些保存文件功能:
没有修改内容前:
查看真实文件:
我们在不使用sandbox的功能的时候,是可以正常读写文件的,如下是我先把sandbox功能关闭:
注意:
有两种方式关闭sandbox:
- 直接在Capabilities中将Sandbox删除
- 不使用证书签名的方式编译,沙盒机制只会在证书签名的方式下才生效。
这里我采用的是第二种方式关闭sandbox,如下图所示,先在buildsetting中搜索Signing选项,找到 “Code Signing Identity” 双击把里面的内容删除。
或者选择Other
- 我们先来看看关闭sandbox的情况:
关闭沙盒后,我们可以随意访问任意的有权限的目录的文件,如下面是我在关闭沙盒的情况下可以访问电脑桌面的任意文件,这里我选择的是:/Users/kongyulu/Desktop/笔记/test.txt
- 这里我增加了再次启动app时读取上一次保存路径的文件功能,如下:
fileprivate func initData() {guard let path = UserDefaults.standard.value(forKey: LastSaveFilePathKey) as? String else {return}filePathField.stringValue = pathlet url = URL(fileURLWithPath: path)do {let text = try String(contentsOf: url)textV.string = text} catch {}}
关闭沙盒的情况下,可以正常访问,并读取到给的路径的文件的内容,如下:
- 接下来我们来加上证书签名,让Sandbox生效,这个时候,我们会发现我刚刚保存的那个沙盒之外的路径在APP启动时不能读取到txt文本的内容了,点击保存按钮也无法将文件修改,这是为啥呢?
苹果爸爸规定:我们程序刚刚启动的时候是不能去访问沙盒之外的路径的,苹果默认只允许访问APP它自己沙盒的内容是不受限制的,如果要访问沙盒之外的路径是需要用户授权的,我们可以调用
NSOpenPanel
类 弹出一个对话框给用户去选择他要打开的文件,当用户点击了OK按钮,则表示用户已经授权了这个文件,这个时候我们需要通过bookmark去保存这个已经授权的文件路径信息(我们可以保存到系统偏好Prefer里面,使用UserDefaults.standard.set(url, forKey: LastSaveFilePathKey)
),下次App启动的时候,直接从bookmark获取到URL ,然后调用allowedURL = [NSURL URLByResolvingBookmarkData:bookmarkData options:NSURLBookmarkResolutionWithSecurityScope|NSURLBookmarkResolutionWithoutUI relativeToURL:nil bookmarkDataIsStale:&bookmarkDataIsStale error:NULL];
函数获取到授权的URL, 这个时候我们去访问url路径下的文件,可以直接访问,它原理用户给定的是什么权限,现在就可以得到什么权限。不需要再次弹出对话框让用户去选择路径授权了。
- 那么问题来了,怎么去保存这个bookmark, 获取它呢,这里我在我的demo里面都给出了方法,可以自己去查看这个demo: 【MacFileAccessInSandbox】
主要涉及到的代码是:
- (BOOL)requestAccessPermissionsForFileURL:(NSURL *)fileURL persistPermission:(BOOL)persist withBlock:(SandboxFileSecurityScopeBlock)block {NSParameterAssert(fileURL);NSURL *allowedURL = nil;// standardize the file url and remove any symlinks so that the url we lookup in bookmark data would match a url given by the askPermissionForURL methodfileURL = [[fileURL URLByStandardizingPath] URLByResolvingSymlinksInPath];// lookup bookmark data for this url, this will automatically load bookmark data for a parent path if we have itNSData *bookmarkData = [self.bookmarkPersistanceDelegate bookmarkDataForURL:fileURL];if (bookmarkData) {// resolve the bookmark data into an NSURL object that will allow us to use the fileBOOL bookmarkDataIsStale;allowedURL = [NSURL URLByResolvingBookmarkData:bookmarkData options:NSURLBookmarkResolutionWithSecurityScope|NSURLBookmarkResolutionWithoutUI relativeToURL:nil bookmarkDataIsStale:&bookmarkDataIsStale error:NULL];// if the bookmark data is stale we'll attempt to recreate it with the existing url object if possible (not guaranteed)if (bookmarkDataIsStale) {bookmarkData = nil;[self.bookmarkPersistanceDelegate clearBookmarkDataForURL:fileURL];if (allowedURL) {bookmarkData = [self persistPermissionURL:allowedURL];if (!bookmarkData) {allowedURL = nil;}}}}// if allowed url is nil, we need to ask the user for permissionif (!allowedURL) {allowedURL = [self askPermissionForURL:fileURL];if (!allowedURL) {// if the user did not give permission, exit out herereturn NO;}}// if we have no bookmark data and we want to persist, we need to create itif (persist && !bookmarkData) {bookmarkData = [self persistPermissionURL:allowedURL];}if (block) {block(allowedURL, bookmarkData);}return YES;
}
这个函数是先去这个请求的路径是否已经保存了,如果保存了是否可以获得它的bookmark, 如果能获取这个bookmkark,则通过
[NSURL URLByResolvingBookmarkData:]
这个方法去获取授权的URL,获得后就可以直接访问路径的文件了,如果没有授权或者保存过bookmark,则从新去弹框,让用户授权。获取授权路径后,需要调用
startAccessingSecurityScopedResource
开启访问权限,在使操作完文件后,需要调用stopAccessingSecurityScopedResource
关闭访问权限,防止恶意程序直接访问文件。
- (BOOL)accessFileURL:(NSURL *)fileURL persistPermission:(BOOL)persist withBlock:(SandboxFileAccessBlock)block {NSParameterAssert(fileURL);NSParameterAssert(block);BOOL success = [self requestAccessPermissionsForFileURL:fileURL persistPermission:persist withBlock:^(NSURL *securityScopedFileURL, NSData *bookmarkData) {// execute the block with the file access permissions@try {[securityScopedFileURL startAccessingSecurityScopedResource];block();} @finally {[securityScopedFileURL stopAccessingSecurityScopedResource];}}];return success;
}
- Swift 代码实现bookmark 权限保存
// MARK: - 沙盒权限
extension AppDelegate {func persistPermissionURL(_ url:URL) {//根据url生产bookmarkDatalet bookmarkData = try? url.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil)print("persistPermissionURL bookmarkData\(url) \(String(describing: bookmarkData))")//存储bookmarkDataif let bookmarkData = bookmarkData {UserDefaults.standard.set(bookmarkData, forKey: url.path)UserDefaults.standard.synchronize()}}func accessFileURL(ofURL url:URL, withBlock block:FilePermissionBlock) -> Bool {let defaults = UserDefaults.standardguard let bookmarkData = defaults.value(forKey: url.path) as? Data else {print("bookmakrData = nil")return false}var bookmarkDataIsStale = falselet allowedUrl = try? URL(resolvingBookmarkData: bookmarkData, options: [.withoutUI, .withSecurityScope], relativeTo: nil, bookmarkDataIsStale: &bookmarkDataIsStale)//bookmarkDataIsStale == true 时,需要重新创建新的bookmarkDataif bookmarkDataIsStale {persistPermissionURL(url)}if let allowedUrl = allowedUrl, allowedUrl.startAccessingSecurityScopedResource() {block()allowedUrl.stopAccessingSecurityScopedResource()return true}return false}
}
3.2.2 Sandbox下访问文件的坑点
Mac 开发(一) 苹果沙盒机制sandbox 简介相关推荐
- Mac 开发(一) 苹果沙盒机制sandbox简介
Mac 开发(一) 苹果沙盒机制sandbox简介 孔雨露正在上传-重新上传取消 2020年06月07日 16:41 · 阅读 7332 @[TOC] Mac 开发(一) 苹果沙盒机制sandbox ...
- iOS开发之沙盒机制(SandBox)
iOS APP可以在自己的沙盒里读写文件,但是,不可以访问其他APP的沙盒.每一个APP都是一个信息孤岛,相互是不可以进行通信的,唯独可以通过URL Scheme.沙盒里面的文件可以是照片.声音文件. ...
- IOS沙盒机制(SandBox)
IOS中的沙盒机制(SandBox)是一种安全体系,它规定了应用程序只能在为该应用创建的文件夹内读取文件,不可以访问其他地方的内容.所有的非代码文件都保存在这个地方,比如图片.声音.属性列表和文本文件 ...
- ios 获取沙河文件夹_iOS开发之获取沙盒路径
iOS开发之沙盒机制(SandBox)详细讲解了沙盒的一些机制.在开发中,我们需要对沙盒进行操作,所以我们需要获取到沙盒路径. 沙盒里的文件夹包括Documents.Library.tmp.这三个文件 ...
- macOS - Cocoa开发之沙盒机制及访问Sandbox之外的文件
原文地址:http://www.skyfox.org/cocoa-macos-sandbox.html iOS默认并且只能读写对应的沙盒目录. OSX自从10.6系统开始引入沙盒机制,规定发布到Mac ...
- IOS 沙盒(sandbox)机制和文件操作
1.IOS沙盒机制( 沙盒(sandbox)机制) IOS应用程序只能在为该改程序创建的文件系统中读取文件,不可以去其它地方访问,此区域被成为沙盒,所以所有的非代码文件都要保存在此,例如图像,图标,声 ...
- iOS沙盒(sandbox)机制和文件操作
本文转载自http://blog.csdn.net/totogo2010/article/details/7671144,感谢作者 1.iOS沙盒机制 iOS应用程序只能在为该改程序创建的文件系统中读 ...
- iOS 开发之沙盒机制 文件操作 (NSFielManager)
原文链接:http://www.jianshu.com/p/349855b5a8ae iOS APP 可以在自己的沙盒里读写文件,但是,不可以访问其他 APP 的沙盒.每一个 APP 都是一个信息孤岛 ...
- iOS开发:沙盒机制以及利用沙盒存储字符串、数组、字典等数据
iOS开发:沙盒机制以及利用沙盒存储字符串.数组.字典等数据 1.初识沙盒:(1).存储在内存中的数据,程序关闭,内存释放,数据就会丢失,这种数据是临时的.要想数据永久保存,将数据保存成文件,存储到程 ...
最新文章
- Corn Fields(POJ 3254状压dp)
- Ajax无刷新实现图片切换特效
- 华中农业大学苏汉东课题组诚聘博士后-
- ASP.NET后台获取url
- [BZOJ5303] [HAOI2018] 反色游戏
- Poj 2503 Babelfish(Map操作)
- 排序 -> 快速排序
- C++11 关键字default和delete
- FileZilla Server连接服务器失败
- docker上安装多个mysql_docker:安装mysql多个
- wps页眉偶数页不同怎么设置_请问在wps文档中如何设置奇偶页不同的页眉
- Hex Editor
- Android系统版本(截止2022年2月)
- IOS 改变导航栏颜色
- 前端团队研发效能提升的探索与实践
- 测试工程师面试题mysql_测试工程师sql笔试题都在这里了!
- 最全的Pandas 日期处理 超强总结!
- FFmpeg源码编译出支持音频AAC编码以及H264,H265编码的库
- 收集android上开源的酷炫的交互动画和视觉效果:Interactive-animation
- Windows10 win+r 历史记录该如何删除
热门文章
- JS/Jquery 中移除子元素的问题
- 电路的基本概念和分析方法
- 信息奥赛一本通1225:金银岛
- 大数据日志分析系统-logstash
- goland编译时提示\go-build\exe\a.out.exe: The process cannot access the file because it is being used
- SpringMVC ResponseBody返回字符串带双引号解决
- Bootstrap3 缩略图( thumbnail )
- VirtualBox:无法访问共享文件夹
- ESP8266-Arduino编程实例-PCF8575IO扩展器驱动
- 数据结构与算法笔记:计算思维之经典农夫过河问题C++实现