APP沙盒的那些坑

掉坑

记得在笨鸟海淘做仓库管理系统的时候,我用Windows写仓库管理软件。当时系统用的是Windows 10。微软的官网对UWP吹得神乎其神,各种设备兼容,一套代码多种设备运行云云,很动人。最后,在功能快完成的时候,掉坑了。APP没有打印的权限。那是我第一次掉进APP沙盒的坑。

最近一次掉沙盒的坑是上周,写PNG Zip的时候。起初,我觉得一周的时间应该能完成所有的工作。最终,我花了一周半的时间。

所以,我觉得我应该跟你分享一下这个掉坑和填坑的过程。看完这篇文章,你应该对沙盒机制有了一定程度的了解,如何在沙盒机制下编程,最后我还会给你一些建议。

在说掉坑填坑之前,我们先了解一下,沙盒是什么。

沙盒是什么

在我们日常用到的操作系统中,应用沙盒机制已经普遍存在了。如iOS、Android、macOS、Windows。由于手机是我们每天都用的贴身工具,里面保存了非常多的隐私数据。所以手机操作系统中,所有应用程序都是沙盒隔离的。而PC系统在这两年也开始推广沙盒的应用,如macOS、Windows 10。今天我要讲的是macOS的沙盒。

我们先来看看沙盒的定义。在Wikipedia中,沙盒是这么定义的。

In computer security, a sandbox is a security mechanism for separating running programs, usually in an effort to mitigate system failures or software vulnerabilities from spreading. It is often used to execute untested or untrusted programs or code, possibly from unverified or untrusted third parties, suppliers, users or websites, without risking harm to the host machine or operating system.
在计算机安全中,沙盒是一种隔离应用程序的机制,通常致力于抑制系统故障或者软件故障的扩散。它通常用于执行未测试的或者不受信任的,来自于未认证或者不受信任的第三方、供应商、用户或者网站的应用程序和代码,以免主机和操作系统受到破坏。

在macOS中,沙盒是这样的。

App Sandbox is an access control technology provided in macOS, enforced at the kernel level. It is designed to contain damage to the system and the user’s data if an app becomes compromised.
应用沙盒是一种由macOS提供的内核级别的访问控制技术。它是为了控制系统或者用户数据受到的破坏而设计的(当一个应用程序受到劫持的时候)。

这两个定义说的意思差不多,就是对应用进行隔离。包括运行环境和用户数据。具体就是说,第一次打开应用,你上不了网,你拍不了照片,你写不了文章。所有的一切你都需要用户授权。

为什么需要沙盒

答案是安全。现如今应用变得非常的复杂。而复杂的系统,不管你多么努力,制定多么严格的安全编程规范,测试得多么地充分,攻击者总能找到漏洞。沙盒的作用就是当你的应用受到攻击时,系统和用户数据受到的破坏能被控制在一定的范围内。

如何在沙盒环境下编程

在沙盒环境下,我们需要做一些权限相关的额外工作。

  • 声明权限
  • 获取权限
  • 保存权限
  • 重新获取权限
  • 释放权限
1)声明权限

在macOS中,通过Entitlements来声明权限。创建xcode工程时,xcode会默认创建appname.entitlements的plist文件。开发者可以编辑这个文件,或者通过target的Capabilities标签配置。

aipng.entitlement

在Capabilities只能声明部分权限,有些权限需要手工编辑.entitlement文件。

2)获取权限

声明了权限后,应用就可以使用相应的编程接口来实现所要的功能。例如,在用户Home目录读写文件。你可以通过NSFileManager提供的API来获取相应的路径。

swift

class NSFileManager

var homeDirectoryForCurrentUser: URL { get }
Objective-C

interface NSFileManager

@property(readonly, copy) NSURL *homeDirectoryForCurrentUser;

对于用户Home目录以外的文件,需要唤起NSOpenPanel来让用户选择,或者通过拖拽的方式将文件拖拽到应用界面中。通过阅读Introduction to Drag and Drop,你可以很快地实现拖拽功能。

3)保存权限

通过用户选择或者拖拽获取到的文件读写权限在应用关闭之后就会丢失。所以,需要一种方法来保存这个权限。macOS给我们提供了Security Scope Bookmark。NSURL提供了对应的接口来创建Security Scope Bookmark

swift 

class NSURL

func bookmarkData(options: NSURL.BookmarkCreationOptions = [], 
includingResourceValuesForKeys keys: [URLResourceKey]?, 
       relativeTo relativeURL: URL?) throws -> Data
Objective-C

interface NSURL

- (NSData *)bookmarkDataWithOptions:(NSURLBookmarkCreationOptions)options 
     includingResourceValuesForKeys:(NSArray<NSURLResourceKey> *)keys 
                      relativeToURL:(NSURL *)relativeURL 
                              error:(NSError * _Nullable *)error;

Security Scope Bookmark以NSData的对象表示。NSData可以持久化到文件,也可以通过IPC等方式发送给其他进程。在应用重启或者另一个进程接收到NSData对象后,即可重新获取权限。如果想要持久化bookmark,可以使用NSData的writeToURL方法。

swift 

class NSData

func write(to url: URL, 
atomically: Bool) -> Bool
Objective-C

interface NSData
- (BOOL)writeToURL:(NSURL *)url 
        atomically:(BOOL)atomically;
4)重新获取权限

Security Scope Bookmark中保存了NSURL的相关信息。我们可以通过NSURL提供的接口重新获得保存的NSURL对象。

swift

class NSURL

convenience init(resolvingBookmarkData bookmarkData: Data, 
         options: NSURL.BookmarkResolutionOptions = [], 
      relativeTo relativeURL: URL?, 
bookmarkDataIsStale isStale: UnsafeMutablePointer<ObjCBool>?) throws
Objective-C

interface NSURL

+ (instancetype)URLByResolvingBookmarkData:(NSData *)bookmarkData 
                                   options:(NSURLBookmarkResolutionOptions)options 
                             relativeToURL:(NSURL *)relativeURL 
                       bookmarkDataIsStale:(BOOL *)isStale 
                                     error:(NSError * _Nullable *)error;

通过NSURL重新获取权限。

swift

class NSURL
func startAccessingSecurityScopedResource() -> Bool
Objective-C

interface NSURL
- (BOOL)startAccessingSecurityScopedResource;
5)释放权限

一旦不再需要使用权限,尽快释放权限。

swift

class NSURL
func stopAccessingSecurityScopedResource()
Objective-C

interface NSURL
- (BOOL)stopAccessingSecurityScopedResource;

人在江湖飘,哪能不挨刀。掉坑总是难免的。NSURL提供了一个很容易让人误用的接口。当我第一眼看到这个接口时,我就把它当作持久化bookmark的接口了。而且这个接口也确实能持久化bookmark数据。然而当你重启应用重新得到NSURL对象后会发现,无法获取权限。

swift

class NSURL

class func writeBookmarkData(_ bookmarkData: Data, 
                          to bookmarkFileURL: URL, 
                     options: NSURL.BookmarkFileCreationOptions) throws
Objective-C

interface NSURL

+ (BOOL)writeBookmarkData:(NSData *)bookmarkData 
                    toURL:(NSURL *)bookmarkFileURL 
                  options:(NSURLBookmarkFileCreationOptions)options 
                    error:(NSError * _Nullable *)error;

实际上,这个接口是用于创建别名链接的。

一些建议

作为开发者,出于降低项目风险和减少工作量的目的。我的建议是尽可能禁用沙盒机制。因为沙盒这个机制还处于发展阶段。权限控制的粒度和编程接口都还没稳定。

可以不开启的场景

  • 内部工具
  • 企业应用
  • 非官方应用商店渠道销售的应用

必须开启沙盒的场景

  • 官方应用商店销售的应用
  • 手机应用

总结

应用沙盒提供了一种隔离机制,使得被劫持的应用能够造成的破坏被限制在一定的范围内。同时,沙盒机制是一把双刃剑。他在提供保护的同时,也加重了开发者的负担,产生额外的辅助数据,占用磁盘空间。甚至在沙盒环境下,部分功能无法实现。

题外话

说到底,这是个信任问题。软件之间、系统之间、人与人之间需要一种信任。当信任缺失的时候,所有参与到其中的任何一方都要付出代价。

参考资料

  1. About App Sandox
  2. Introduction to Drag and Drop
  3. NSURL文档
  4. NSData文档
  5. NSFileManager文档
  6. Swift编程指南
  7. Objective-C编程指南
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,858评论 6 13
  • 218.241.181.202 wxhl60 123456 192.168.10.253 wxhl66 wxhl6...
    CYC666阅读 1,361评论 0 6
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • 本文是昨天寫的,忘記發了。今天補發。稍瑞啊。各位親。 今天是2017年3月28日,星期二。 我們繼續聊聊減肥。昨天...
    王玨新派中醫阅读 222评论 0 0
  • 第1章 三生馆,三生酒 三生山中一小镇,小镇名唤寒镇,镇上有一酒馆,名唤三生馆,馆内只卖一种酒,名唤三生酒。 ...
    杜兹肺魚阅读 566评论 1 1