“iOS应用安全权威指南”读书笔记-“第一部分”

“iOS应用安全权威指南”读书笔记

        “第一部分”为iOS基础,共包括一、二、三章

第一章:iOS安全模型

        App Store对开发者来说,应用程序的审核流程是令人沮丧的黑箱操作。苹果的审核流程和方法并不对外公开,有时候你搞不清楚什么功能允许使用,什么功能禁止使用。苹果提供了正式的知道手册(https://developer.apple.com/appstore/resources/approval/guidelines.html),但是遵守了指导的应用同样会被拒绝。

        苹果使用App Store来控制和限制iOS平台上应用程序的功能,这就意味着如果想要实现某些特定的功能,唯一的手段就是将设备越狱或骗过应用商店的审查。

        官方的应用审查永远无法抓到那些钻空子的恶意程序,所以需要另外一套高效的机制,来阻止恶意程序破坏整个操作系统的安全。

        先来看一下iOS基本的安全组件是如何阻止恶意攻击和保护数据的。

安全启动

        当启动一台iOS设备时(开机),系统首先会从只读的引导ROM中读取初始化指令,即系统引导程序。这个引导ROM包含苹果官方权威认证的公钥,它会验证底层启动加载器(LLB)的签名,一旦通过验证就启动它(它指LLB)。LLB会做一些基础工作,然后验证第二级引导程序iBoot。iBoot启动后,设备就可以进入恢复模式或启动内核。在iBoot验证完内核签名的合法性之后,整个启动程序进入正轨:加载驱动程序、检验设备、启动系统守护进程。

        这个信任链确保所有的系统组件都由苹果写入、签名、分发。应用程序启动时也会用信任链去审查签名。所有的应用都必须直接或间接由苹果签名。

        越狱的工作原理正是攻击这一信任链。越狱工作的作者需要找到这一信任链条上的漏洞,从而禁掉链条中负责验证的组件。破解引导ROM通常是最可取的方式,因为该组件不会因苹果今后的软件更新而改变。

沙盒机制

        苹果的沙盒机制,历史上被称为安全带,是一种基于FreeBSD系统TrustedBSD框架的强制访问控制(MAC)机制。它采用一种类似Lisp的配置语言来描述哪些资源系统可以访问,哪些禁止访问。这些资源主要包括文件、系统服务、网络连接、内存资源等。

        MAC机制不同与传统的访问控制机制(比如自助访问控制(DAC)),它不允许主体操作对象。DAC最常见的形式就是UNIX系统的用户、组和其他权限,所有这些都可以被授予读、写、或执行的权限。在DAC系统中,用户如果拥有一个对象的所有权,也就拥有该对象的修改权限

        在OS X中你可以部分控制应用程序的沙盒功能,但是在iOS平台中,一般只能访问应用程序的包目录:应用可以读写储存在该位置的文件。(也有例外,图片在应用程序包目录之外,但第三方应用程序还是可以直接访问)

        安卓的访问机制与MAC不同,安卓实现了一个更加传统的DAC模型,应用程序都有自己的用户ID和属于该ID的文件夹,其权限管理严格按照传统的UNIX文件权限管理运作。虽然MAC和DAC这两种机制工作起来都没有问题,但MAC的扩展性总体来说还是更强一些。比如,除了应用程序目录隔离,MAC还可以限制网络访问或系统守护进程的操作

数据保护和全盘加密

        iOS一直是移动设备文件加密的先去。iOS提供全盘加密,还为开发者提供了数据保护API,用于进一步保护自己的文件。这两个机制可以实现远程抹除设备数据,在设备丢失的情况下保护用户数据免于泄漏

        iOS设备通常为全天候运行设计,它们的内部储存不容易被轻易拆卸。如果一个攻击者想要不通过验证就从设备中获取敏感信息,他必须把设备完全拆解,然后将闪存连接到一个自定义的接口来直接读取数据。不过从设备中获取数据有几个更简单的方法:代码执行漏洞、越狱等,因此几乎没有人会去拆手机。

        但这并不意味着iOS的全盘文件系统加密毫无用处,它对于下面两个安全特性来说是必要的:安全删除文件、远程设备擦除。传统安全擦除文件的方法不适用于iOS设备,主要原因是iOS设备使用固态磁盘SSD作为储存。固态磁盘采用了减少磨损的机制,因此执行覆盖文件的操作无法真正覆盖硬盘中的旧数据。解决方案是确保文件被一个安全位置上的密钥加密,这样请求销毁数据时,可以直接丢弃该密钥。iOS中使用的密钥加密是分层级的,只需简单地丢弃一个加密密钥就能够彻底销毁整层的数据,甚至是销毁整个文件系统。

        加密密钥的层级

        iOS文件系统中用于数据加密的密钥是分等级的,也就是说,用密钥来加密其他密钥,这样苹果就能更精确的控制数据什么时候可用。一个基本的分层结构如图1-1所示:

1-1 iOS加密密钥层级

        文件密钥File Key⑤是针对每个文件独立生成,储存在文件的元数据中。不同保护级别的文件需要使用不同强度的加密密钥。

        层级密钥Class Key④的作用是专门为那些特殊数据提供不同级别的保护。在最先的iOS版本中,默认的保护等级是NSFileProtectionNone;从iOS5开始,默认的保护等级变成了NSFileProtectionCompleteUntilFirstUserAuthentication。

        文件系统密钥Filesystem Key③是一种全局加密密钥,当元数据被层级密钥加密后,我们使用文件系统密钥来加密涉及文件安全的元数据。

        设备密钥Device Key①通常被称为UID密钥,每一台设备唯一,只能通过硬件的AES引擎访问,操作系统无法直接获得。这是系统的主密钥,它用来加密文件系统密钥和层级密钥。如果启用了用户密码User Passcode②,它将与设备密钥结合起来加密层级密钥。

        一旦设置密码,这个密钥等级也允许开发者自己决定本地储存的数据该如何被保护,包括在设备锁定时是否能被访问、数据能否备份到其他设备等。

        钥匙串API

        iOS提供了要钥匙串API来储存少量机密信息。开发者可以用来储存密码、加密密钥一级那些不能被其他应用访问的敏感信息。调用钥匙串API主要通过securityd守护进程来完成,即从SQLite数据库中提取数据。开发者可以指定在什么情况下应用可以读取密钥,这和数据保护API类似。

        数据保护API

        数据保护API利用文件系统加密、钥匙串和用户密码,提供了一个额外的针对文件的保护层,开发者可以根据需要使用。这限制了某些进程在系统层面上读取文件。这个API最常用的场景是当设备锁定时确保数据不可用。

        数据保护的强度很大程度上取决于iOS设备运行的版本。随着版本更迭,默认的数据保护等级会发生变化。在新创建的iOS应用程序中,数据保护默认对所有应用数据开启,这种状态在启动设备后的第一次解锁都生效。可在Xcode-Capabilities中有个Data Protection默认已打开。

防御代码漏洞:ASLR、XN和其他机制

        iOS使用两套标准机制来预防代码执行攻击:地址空间结构随机化(ARLR)XN bit(eXecute Never的缩写,标记该段内存区域不包含可执行代码)。每次执行程序时,ASLR都会随机分配程序、数据、堆和栈的内存位置。共享库的内存位置只在每次系统重启时随机设置。函数和库的内存地址很难预测,这就预防了缓冲区溢出攻击(return-to-libc),这种攻击依赖于基本库函数的已知地址。

        XN bit,一般对应非ARM平台的NX(No-eXecute)bit,允许操作系统将某段内存标记为不可执行,这是由CPU来控制的。在iOS中,这个机制默认应用在程序的栈和堆上。这意味着,哪怕攻击者可以将恶意代码注入程序的堆和栈,他们也无法重定向程序来执行攻击代码。

        每个程序都有一段既能写又能执行的内存,前提是它必须经过苹果官方签名授权系统的签名。Safari浏览器中的JavaScript即时(JIT)编译器会用到这段内存。你平时在程序中经常使用的WebView并不具备访问相同功能的权利,这样就可以避免代码执行攻击。苹果一直禁用第三方的JIT,如Chrome就没有Safari那样好用,Chrome只能使用WebView。

越狱检测

        越狱的本质就是通过一系列步骤来禁掉签名机制,从而允许设备运行未经苹果官方审核的应用。越狱还允许你使用一些便利的开发和测试工具。越狱还有一个直观重要的能力,就是黑箱测试应用程序(第六章讨论)。

        越狱不一定要禁掉iOS的沙盒机制,它只是允许你在沙盒外安装应用程序。安装在移动用户主目录的应用程序(即通过苹果商店安装)仍然受到沙盒限制。第三方的iOS应用程序需要安装在越狱设备中权限更高的/Applications目录下。

        越狱检测很早就有,不过没什么用。它的目的是检测设备是否存在不受信任、未经前面的第三方程序,从而判断设备是否处在高风险环境中。总体来说,越狱检测不值得你浪费时间去做,因为它无法阻止一个坚定的攻击者。

        有一段时间,苹果官方推出过越狱检测API,但很快就在后续的iOS版本中删掉了。没有此API,开发者也实现了一些越狱检测方法。目前最流行的越狱检测方法主要有下面几种:

        1、创建一个新进程,例如调用fork()、vfork()、popen()等方法。这些方法是明显会被沙盒所禁止的事情。当然,越狱系统上的沙盒仍然有效,所以该策略毫无意义,无论你的设备越狱与否,这种方法对于来自苹果官方商店的程序来说始终是无效的。

        2、读取沙盒外部的文件。开发者通常想要尝试访问一些二进制代码,这些二进制代码通常对应于ssh、bash,还有一些位于Cydia.app目录和Cydia经常使用的apt仓库等位置。但这些检测很容易被绕过,并且Xcon6之类的工具也能帮助用户绕过这些自动检查。

        3、检查是否有相关的方法名。所以不要取名如isJailbroken类似的直白方法名,否则攻击者可以轻易定位并禁掉越狱检测。

举个栗子:精明的开发者会尝试使用_dyld_image_count()和_dyld_get_image_name()来检查载入的动态库数量和名字,并使用_dyld_get_image_header()来检查它们在内存中的位置。但是攻击者可以通过给应用打一个二进制补丁来绕过这些检测。

       总结来说,越狱检测只会减慢攻击者的攻击时间,并不能真正阻止鉴定的攻击者。所以并没有什么卵用。

苹果商店的审查是否有用

        当开发一个应用或评估其面对的威胁时,需要将用户设备上其他应用考虑进来。设备上任何恶意的第三方应用程序都能通过IPC机制与其他应用交互,也能窃取用户私人信息。苹果官方的应用程序审查是对抗这些恶意程序最有利的武器

        苹果并没有公开披露他们的审查技术。可以确定都是,苹果使用了二进制分析和动态测试技术。这一过程可以将大部分带有明显恶意的应用程序拒之门外。尽管苹果付出了很大努力,但是事实证明,一个中等水平的攻击者完全有能力伪装一个动态代码更新应用,让它通过苹果商店的审查。攻击者一般通过以下几种方式来蒙混过官方商店的审查。

        1、WebKit桥接:基于WebKit桥接,可以通过JavaScript使用一些iOS的原生API。如PhoneGap(即现在的Cordova框架)。这种方式可以提供很多有用的功能,但使用它们也意味着应用程序的许多逻辑要写成JavaScript,因此不需要打包到应用中。举个栗子:一个开发者使用JavaScript实现了一个常规的打开文件功能,然后在应用程序审核期间不做任何的恶意操作。一旦审核通过,开发者可以修改设备的JavaScript,从而获取设备上那些本应该是禁区的数据。(第九章将详细介绍JavaScript与原生代码的桥接和需要注意的问题)

        2、动态修复:通常来说,如果一段代码没有经过苹果发布的密钥签名认证,应用程序则无法运行它。iOS有一个特性,可以让程序分配一段没有NX保护的内存区域(即该内存区块可读可写可执行),里面运行的代码也不需要经过签名认证。这一机制被苹果用在了Safari的JIT编译器上,以便实现一些功能。但是苹果在实现的过程中可能会产生漏洞,这样第三方应用程序就可以执行相同的把戏。举个栗子:应用审查期间,该应用安分守己,但是一旦通过审查,就远程操控程序下载新的、未经签名的代码并执行,整个过程毫无阻碍。当然现在这个问题已经解决了,但是它却为我们如何骗过审查提供了思路。

        3、故意植入不安全的代码:恶意代码被打包在应用程序自身之中以便其顺利可以得到签名,同样在审查时应用程序从不去调用这些代码。一旦获准上架,研究人员能够利用缓冲区溢出得到漏洞改变应用程序的控制流,使其导向隐藏的恶意代码。

        4、内嵌解释器:过去几年,苹果在有许多产品(主要是游戏)使用一个内嵌的Lua解释器来执行大部分的内在逻辑。恶意程序应用可以通过一个类似的解释器来动态下载代码,并在内存中执行。当然,在官方的应用审查时这类恶意代码还是会隐藏自己。通过此方法我们能增加一个新的功能,行为不端的开发者也能较为便利地添加一个恶意功能。

小结

        苹果的审查可以帮我们消除那些简单的恶意程序,但是恶意程序的确可以有方法从审查人员的眼皮底下溜走。时刻记住在你的应用程序中用代码做好防御。


第二章:Objective-C简明教程

        只能说稳固而知新吧。简要的写一下这章看有没有值得记录的内容。

        关键的iOS编程技术

        Cocoa是一些框架和Objective-C GUI编程API的总称。Cocoa Touch是Cocoa的一个超集,主要加入了一些移动相关的API,如手势处理和移动设备图形用户界面元素。Foundation类是Objective-C类,它构成了我们调用的Cocoa API。Core Foundation是一种更低级的基于C的类库,在其上有很多Foundation类。

        .m文件的一个例子:

@interface Kitty : NSObject {

    @private NSString *name;

    @protected NSURL *homepage;

    @public NSString *color;

}

@private只允许从定义该变量的类的内部访问,@protected允许从定义变量的类及其子类中访问,@public可以从任何类中访问。默认不写情况下是@protected。

        Objective-C为.h和.m,C++为.h和.cpp,Objective-C++(混合了C++和Objective-C的代码)是.h和.mm文件

        Objective-C中没有内存管理机制,它使用自动引用计数ARC来对内存进行管理。

        Core Foundation对象可以通过 __bridge 系列关键字来桥接Cocoa对象。

        Objective-C的一些委托方法通常使用should、will、did来修饰一些方法名。should修饰,通常返回值为BOOL,可以返回相应的YES、NO来做到是否允许执行的操作。will代表程序将要执行某些操作,如果viewWillAppear:告诉你视图即将出现,你就可以在视图出现之前做一些操作。did表示已经进行,如viewDidAppear:告诉你视图已经出现。我们写代码的时候也可以遵循类似的规则。

        Objective-C的category机制允许你在运行时给现有的类添加新的方法实现,而且不用重新编译。category可以添加或替换类的方法实现,因此,你不用重新实现这个类就能轻松修改它的行为。不幸的是,使用category很容易导致严重的安全问题,因为它们可以通过代码块从任意位置侵入你的类

        苹果官方对于category是这样说的:如果你在category中声明了一个和原类同名的方法,或和该类的另一个category中的方法重名,那么在运行时究竟哪个方法会被执行是不确定的。

        所以结论是:category确实方便,但是尽量少用,它们可能会弄乱代码,并危害安全

        使用方法swizzling可以替换现有类方法和实现方法,哪怕你根本不拥有这些方法。方法swizzling功能上类似于category的子类化,但是比category更加强大也更方便,你可以直接把原有的方法实现替换    为新的方法实现,而不是扩展原方法。开发者往往使用这项技术实现子类们都需要的通用方法。

        如果想要使用swizzling,那么推荐使用便于测试的封装包,如JRSwizzle。如果应用使用swizzling做了一些有风险的事情,苹果可能会拒绝应用上架。


第三章:iOS应用剖析

        要找出应用在本地储存的所有数据,最快的方法是查看~/Library/Developer/CoreSimulator/Devices目录。从Xcode6开始,只要在模拟器上运行过应用,Xcode就会根据当前设备了类型和系统版本建立一个文件夹并分配一个UUID。相关的应用数据被储存在这个目录下的两个位置。其中应用的二进制和资源文件(包括.nib文件和图形文件)都放置在<device ID>/data/Containers/Bundle/Application/<app bundle id>目录下。而经常变化的动态数据则储存在~<device ID>/data/Containers/Data/Application/<app bundle id>目录中。系统数据(如全局配置文件)将储存在其余的目录下。

        右键Finder,前往文件夹输入~/Library/Developer/CoreSimulator/Devices,可看到如下图片内容:

~/Library/Developer/CoreSimulator/Devices

    随便点进一个

    1、查找二进制和资源文件目录(<device ID>/data/Containers/Bundle/Application/<app bundle id>)

    2、查看下动态数据目录(<device ID>/data/Containers/Data/Application/<app bundle id>)

对该目录结构进行一下探索,可以勾画出下图的大体轮廓:

        可以使用iExplorer工具来查看安装应用程序的目录结构。

        本章,我将介绍一些常见的目录和iOS应用经常储存的数据,还会介绍如何通过代码的方式与其交互,以及什么数据可能会从中泄漏。

对plist文件进行处理

        iOS将应用程序的配置数据储存在属性列表plist文件中,这些信息都是Core Foundation数据类型,比如CFArray和CFString。从安全角度说,你需要重点检查plist文件中是不是纯文本的值, 比如证书,它们有可能会被修改从而改变应用程序的行为。举例来说,默认情况下,支付功能是被禁用的,但是当相应的值被修改时,该功能就可以被使用。

        属性列表有两种格式:二进制和XML。如下XML格式就有很好的可读性。

XML格式的plist

        如果用命令行查看文件或在代码中处理plist,就会经常遇到二进制格式的plist文件。二进制格式的可读性对我们而言并不是那么理想,不过你可以使用plutil(1)命令将plist文件转换成XML格式。

$ plutil -convert xmll Info.plist -o -

$ plutil -convert xmll Info.plist -o Info-xml.plist

$ plutil -convert binary1 Info-xml.plist -o Info-bin.plist

        第一条命令将一个二进制的plist转换成XML,然后打印到标准输出(stdout),之后可以通过管道pipe把内容传给less(1)或者类似的命令。

        第二条命令使用-o filename参数直接将内容输出到一个文件。

        第三条命令,binary1转换类型将XML格式的plist转换成二进制格式。

其实XML和二进制格式都能被应用识别,所以也可以不做转换。

设备目录

        从iOS8开始,模拟器平台(比如iPhone、iPad以及其他的变体设备)都储存在以唯一标识符命名的目录下。这些标识符由两部分组成:一部分是从Xcode启动模拟器时选择的设备类型,另一部分是系统版本。所有目录都有一个plist文件记录当前的设备信息。下面是一个例子:(如前往文件夹~/Library/Developer/CoreSimulator/Devices,进去任意一个设备目录,可以找到device.plist文件,用文本编辑器打开)

device.plist

在这个plist文件中,想找出设备信息并不容易。为了找出设备信息,要么去①Devices目录下查看.default_created.plist文件,要么使用②grep命令找出所有的device.plist文件。

        ①:我没找到.default_created.plist或者default_created.plist文件。。不知道是不是书中写错了还是我找的目录错了。我找到了一个device_set.plist文件,里面确实有很多device的信息。

        ②:使用grep命令:

用grep命令来确定iOS设备模型所对应的标识符

    进入正在运行的应用程序目录后,你会看到data目录,它包含所有的模拟器文件,还包含应用相关的数据。应用数据被分别放到了三个目录中,它们在data/Containers目录下,分别是Bundle、Data、Shared目录:

Bundle目录:

        Bundle目录中有一个Applications目录,该目录包含设备上所有的应用目录,这些应用目录用bunle ID命名。进入某个应用目录,看到.app文件,右键,显示包内容。.app文件储存应用程序的核心二进制代码、图像资源、本地化信息等,其中Info.plist包含应用程序的核心配置信息,包含bundle id,主程序包、应用程序的UI信息以及应用程序需要向设备请求的功能。Info.plist中值得关注的一个条目是UIRequiredDeviceCapabilities,该条目描述了应用所需要的系统资源(非必须的条目)。

UIRequiredDeviceCapabilities

Data目录

    Data目录中最重要的是Application子目录。Data/Application目录包含了应用程序运行所需的其他数据:参数设置、缓存、cookie等。这个目录也是需要重点检查的对象,因为大部分数据泄露都发生于此

~Library/Developer/CoreSimulator/Devices/<bundle ID>/data/Containers/Data/Application/<app bundle id>/(Doucuments、Library、tmp)

        Documents和Documents/Inbox目录

        Doucuments目录主要用来储存非临时状态的应用数据,比如用户创建的内容或应用程序在离线状态模式下需要的本地缓存信息。如果你在Info.plist中设置了UIFileSharingEnabled,那么可以通过iTunes访问这些文件。

        其他应用发送过来的文件储存在Documents/Inbox目录中。这些应用可以使用UIDocumentInteractionController类来发送文件。

        你只能读取或者删除储存在Inbox目录下的文件。这些来自其他应用程序的文件不能写入你的应用目录里,它们将被一个优先级更高的系统进程处理。你可以定期删除这些文件,也可以让用户选择是否删除,这样用户就可以知道这里有没有敏感信息。

        如果你正在开发一个应用,想确保磁盘上不会遗留任何敏感信息,那么可以将Inbox目录中的文档复制到另一个位置,从而对数据进行保护,然后从Inbox目录中移除这些文件。

Library目录

        从之前的结构图看到,Library下有Application Support、Caches、Cookies、Preferences、Saved application state目录。

Library目录下的文件可以通过iTunes和iCloud进行备份(Caches目录除外)

        Application Support目录

        由用户创建和接收的文件不会储存在Application Support目录中,该目录主要用来储存应用程序使用的数据文件该目录下的文件主要用来支持应用程序运行。这些文件可以在应用程序安装时部署,也可以在应用程序创建或从网络上下载。(我的理解:不管你的来源如何,反正用途就是支持应用程序运行)

        默认情况下,iTunes会备份这个目录下的数据到你的计算机和iCloud中。但是如果你不放心将数据保存到苹果的云端,可以通过为新创建的文件设置NSURLIsEXecutedFromBackupKey属性来禁止备份到云端。

        值得一提的是:苹果只要求应用备份用户数据到iCloud,不要求应用备份应用数据。如果一个程序允许备份应用数据到iCloud,那么该应用一定会被App Store拒绝上架的。

        Caches和Caches/Snapshots目录

        Caches目录在功能上类似于网页浏览器缓存:所以iTunes不会备份该目录Caches目录用来存放临时内容,随着应用程序的启动和退出,这些内容将会被丢弃iOS系统在运行空间不足时会自动删除这些缓存目录,不过并不会删除当前正在运行程序的缓存

        Caches目录有时也会把网页缓存内容储存在子目录Caches/com.mycompany.myapp中。该位置有容易泄露敏感信息,因为通过HTTPS进行长时间传输的数据可以被iOS缓存,如果开发者没有禁止数据缓存或尽快使缓存数据过期,那么攻击者总能在这里唱到甜头。

        当应用程序进入后台,操作系统会自动把当前应用的屏幕快照储存到Snapshots子目录中,这样做会无形中把一些敏感信息储存在本地。操作系统这样做的目的:当应用切回前台时,操作系统可以使用它的屏幕快照创建一个快速的动画。(比如截图有可能会包含用户的社会保险号码等等等敏感信息)(看到工行的App做的挺好的,在应用切回前台的时候,这张快照是模糊的,具体怎么操作有待考虑)。

        Cookies目录

        由URL加载系统所产生的cookie都储存在Cookies目录中。创建NSURLRequest请求时,你将指定相关的cookie策略,或者使用系统默认的策略。与OS X系统不同,iOS上的cookie不会在应用之间共享,每个应用都有单独的目录来储存自己的cookie。

        Preferences目录

        iOS将应用的偏好设置储存在此Preferences目录下,但是不允许应用直接编辑目录中的文件。取而代之,此目录下文件的创建、读取、操作都通过NSUserDefaultsCFPrefrences API来完成。

        请不要将敏感的用户信息或证书储存在此。

        Saved application state目录(保存应用程序状态的目录)

        用户期待应用能记住他们输入文本框的内容和启用的设置。如果一个用户切换到另一个应用,片刻后又切换回来,原先的应用可能已经在后台被系统杀掉了。为了在应用启动时使它的界面和之前保持一致,新版本的iOS通过State Preservation API将对象状态信息储存在Saved Application State目录中。开发者可以将需要保存的状态的UI标记出来。

        在保存应用状态时要相当小心,这也是一个容易泄露数据的地方。(第10章将深入讨论如何避免数据泄露)。

        tmp目录

        tmp目录用来储存临时文件。和Caches目录一样,当你的应用停止运行时,该目录中包含的文件可能会被操作系统自动删除。此目录的使用方法和Caches目录类似。不同之处在于Caches意味着缓存的这些文件可能会被再次获取或重新创建。比如,你从远程服务器下载了特定的应用数据,为了提高性能,会将数据缓存在Caches目录中,如果数据消失了,可以重新去下载。另一方面,tmp目录严格储存着由应用产生的临时数据,如果这些文件在重新访问前被删除,你并不能重新获取到它们。此外,tmp目录和Caches目录一样,都不会备份到iTunes和iCloud

Shared目录

        Shared目录是一个特殊的目录,用来为应用程序提供一个共享的应用组(为了支持iOS8的扩展(extentions)),比如修改通知中心“今日”视图中的任务或键盘行为。苹果要求所有的扩展都必须对应一个容器应用,每一个容器应用都会拥有自己的应用ID。扩展及其容器应用可以通过Shared目录来共享数据。例如:应用可以使用NSUserDefaults的初始化方法,指定一个名字来访问用户数据中共享的数据库,类似于这样:[[NSUserDefaults alloc] initWithSuiteName:@"com.myorg.mysharedstuff"];

        Shared目录在日常开发中并不常用,但当我们检查储存在preferences中的敏感信息或其他隐私数据时,别忘了这个目录。

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

推荐阅读更多精彩内容