跳过内容

MASTG-TEST-0052: 测试本地数据存储

此测试即将更新

此测试目前可使用,但将作为新的 OWASP MASTG v2 指南 的一部分进行全面修订。

请提交 PR 以帮助我们完成以下任务:MASTG v1->v2 MASTG-TEST-0052:测试本地数据存储 (ios)

发送反馈

概述

此测试用例侧重于识别应用程序存储的潜在敏感数据,并验证是否安全存储。 应执行以下检查

  • 分析源代码中的数据存储。
  • 务必触发应用程序中的所有可能功能(例如,通过单击所有可能的位置),以确保数据生成。
  • 检查所有应用程序生成和修改的文件,并确保存储方法足够安全。
    • 这包括 NSUserDefaults、数据库、KeyChain、内部存储、外部存储等。

注意: 对于 MASVS L1 合规性,将数据未加密地存储在应用程序的内部存储目录(沙盒)中就足够了。 对于 L2 合规性,需要额外的加密,使用在 iOS KeyChain 中安全管理的加密密钥。 这包括使用信封加密 (DEK+KEK) 或等效方法。

静态分析

当您可以访问 iOS 应用的源代码时,请识别在整个应用中保存和处理的敏感数据。 这包括密码、密钥和个人身份信息 (PII),但也可能包括行业法规、法律和公司政策确定的其他敏感数据。 查找通过下面列出的任何本地存储 API 保存的此数据。

确保敏感数据永远不会在没有适当保护的情况下存储。 例如,身份验证令牌不应在没有额外加密的情况下保存在 NSUserDefaults 中。 此外,避免将加密密钥存储在 .plist 文件中,硬编码为代码中的字符串,或使用基于稳定属性的可预测的混淆函数或密钥派生函数生成密钥。

敏感数据应使用 Keychain API(将其存储在安全 Enclave 内部)存储,或使用信封加密加密存储。 信封加密或密钥包装是一种密码构造,它使用对称加密来封装密钥材料。 数据加密密钥 (DEK) 可以使用密钥加密密钥 (KEK) 进行加密,KEK 必须安全地存储在 Keychain 中。 加密的 DEK 可以存储在 NSUserDefaults 中或写入文件中。 需要时,应用程序读取 KEK,然后解密 DEK。 请参阅 OWASP 加密存储备忘单,了解有关加密加密密钥的更多信息。

Keychain

必须实现加密,以便密钥以安全设置存储在 Keychain 中,理想情况下为 kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly。 这可确保使用硬件支持的存储机制。 确保 AccessControlFlags 根据 KeyChain 中密钥的安全策略进行设置。

使用 KeyChain 存储、更新和删除数据的通用示例可以在官方 Apple 文档中找到。 官方 Apple 文档还包括一个使用 Touch ID 和密码保护的密钥的示例。

文件系统

使用源代码,检查用于在本地存储数据的不同 API。 确保根据数据的敏感性正确加密任何数据。

动态分析

确定敏感信息(如凭据和密钥)是否在不利用本机 iOS 函数的情况下不安全地存储的一种方法是分析应用的数据目录。 在分析数据之前触发所有应用功能非常重要,因为应用可能仅在触发特定功能后才存储敏感数据。 然后,您可以根据通用关键字和特定于应用的数据对数据转储执行静态分析。

以下步骤可用于确定应用程序如何在越狱的 iOS 设备上本地存储数据

  1. 触发存储潜在敏感数据的功能。
  2. 连接到 iOS 设备并导航到其 Bundle 目录(这适用于 iOS 8.0 及更高版本):/var/mobile/Containers/Data/Application/$APP_ID/
  3. 使用您存储的数据执行 grep,例如:grep -iRn "USERID"
  4. 如果敏感数据以纯文本形式存储,则该应用未通过此测试。

您可以使用第三方应用程序(如 iMazing)在非越狱的 iOS 设备上分析应用的数据目录。

  1. 触发存储潜在敏感数据的功能。
  2. 将 iOS 设备连接到主机并启动 iMazing。
  3. 选择“Apps”,右键单击所需的 iOS 应用程序,然后选择“Extract App”。
  4. 导航到输出目录并找到 $APP_NAME.imazing。 将其重命名为 $APP_NAME.zip
  5. 解压缩 ZIP 文件。 然后,您可以分析应用程序数据。

请注意,iMazing 等工具不会直接从设备复制数据。 他们尝试从他们创建的备份中提取数据。 因此,无法获取 iOS 设备上存储的所有应用数据:并非所有文件夹都包含在备份中。 使用越狱设备或使用 Frida 重新打包应用程序,并使用像 objection 这样的工具来访问所有数据和文件。

如果您将 Frida 库添加到应用并按照“非越狱设备上的动态分析”(来自“iOS 上的篡改和逆向工程”一章)中的描述重新打包了它,则可以使用 objection 直接从应用的数据目录传输文件,或如 主机-设备数据传输 中解释的那样,在 objection 中读取文件

可以使用不同的工具在动态分析期间转储 Keychain 内容,请参阅 转储 KeyChain 数据

Keychain 文件的路径是

/private/var/Keychains/keychain-2.db

在非越狱设备上,您可以使用 objection 转储由应用创建和存储的 Keychain 项目。

使用 Xcode 和 iOS 模拟器进行动态分析

此测试仅在 macOS 上可用,因为需要 Xcode 和 iOS 模拟器。

对于测试本地存储并验证其中存储的数据,拥有 iOS 设备不是强制性的。 通过访问源代码和 Xcode,可以在 iOS 模拟器中构建和部署应用程序。 当前 iOS 模拟器设备的文件系统位于 ~/Library/Developer/CoreSimulator/Devices 中。

一旦应用程序在 iOS 模拟器中运行,您可以使用以下命令导航到上次启动的模拟器的目录

$ cd ~/Library/Developer/CoreSimulator/Devices/$(
ls -alht ~/Library/Developer/CoreSimulator/Devices | head -n 2 |
awk '{print $9}' | sed -n '1!p')/data/Containers/Data/Application

上面的命令会自动找到上次启动的模拟器的 UUID。 现在您仍然需要在您的应用程序中 grep 您的应用程序名称或关键字。 这将显示应用程序的 UUID。

grep -iRn keyword .

然后,您可以监视和验证应用程序文件系统中的更改,并调查在使用应用程序时是否在文件中存储了任何敏感信息。

使用 Objection 进行动态分析

您可以使用 objection 运行时移动探索工具包来查找由应用程序的数据存储机制引起的漏洞。 Objection 可以在没有越狱设备的情况下使用,但它需要修补 iOS 应用程序

读取 Keychain

要使用 Objection 读取 Keychain,请执行以下命令

...itudehacks.DVIAswiftv2.develop on (iPhone: 13.2.3) [usb] # ios keychain dump
Note: You may be asked to authenticate using the devices passcode or TouchID
Save the output by adding `--json keychain.json` to this command
Dumping the iOS keychain...
Created                    Accessible                      ACL    Type      Account                    Service                                                        Data
-------------------------  ------------------------------  -----  --------  -------------------------  -------------------------------------------------------------  ------------------------------------
2020-02-11 13:26:52 +0000  WhenUnlocked                    None   Password  keychainValue              com.highaltitudehacks.DVIAswiftv2.develop                      mysecretpass123

搜索二进制 Cookies

iOS 应用程序通常将二进制 cookie 文件存储在应用程序沙盒中。 Cookie 是包含应用程序 WebViews 的 cookie 数据的二进制文件。 您可以使用 objection 将这些文件转换为 JSON 格式并检查数据。

...itudehacks.DVIAswiftv2.develop on (iPhone: 13.2.3) [usb] # ios cookies get --json
[
    {
        "domain": "highaltitudehacks.com",
        "expiresDate": "2051-09-15 07:46:43 +0000",
        "isHTTPOnly": "false",
        "isSecure": "false",
        "name": "username",
        "path": "/",
        "value": "admin123",
        "version": "0"
    }
]

搜索属性列表文件

iOS 应用程序通常将数据存储在属性列表 (plist) 文件中,这些文件存储在应用程序沙箱和 IPA 包中。 有时,这些文件包含敏感信息,例如用户名和密码;因此,在 iOS 评估期间应检查这些文件的内容。 使用 ios plist cat plistFileName.plist 命令来检查 plist 文件。

要查找文件 userInfo.plist,请使用 env 命令。 它将打印出应用程序的 Library、Caches 和 Documents 目录的位置

...itudehacks.DVIAswiftv2.develop on (iPhone: 13.2.3) [usb] # env
Name               Path
-----------------  -------------------------------------------------------------------------------------------
BundlePath         /private/var/containers/Bundle/Application/B2C8E457-1F0C-4DB1-8C39-04ACBFFEE7C8/DVIA-v2.app
CachesDirectory    /var/mobile/Containers/Data/Application/264C23B8-07B5-4B5D-8701-C020C301C151/Library/Caches
DocumentDirectory  /var/mobile/Containers/Data/Application/264C23B8-07B5-4B5D-8701-C020C301C151/Documents
LibraryDirectory   /var/mobile/Containers/Data/Application/264C23B8-07B5-4B5D-8701-C020C301C151/Library

转到 Documents 目录并使用 ls 列出所有文件。

...itudehacks.DVIAswiftv2.develop on (iPhone: 13.2.3) [usb] # ls
NSFileType      Perms  NSFileProtection                      Read    Write    Owner         Group         Size      Creation                   Name
------------  -------  ------------------------------------  ------  -------  ------------  ------------  --------  -------------------------  ------------------------
Directory         493  n/a                                   True    True     mobile (501)  mobile (501)  192.0 B   2020-02-12 07:03:51 +0000  default.realm.management
Regular           420  CompleteUntilFirstUserAuthentication  True    True     mobile (501)  mobile (501)  16.0 KiB  2020-02-12 07:03:51 +0000  default.realm
Regular           420  CompleteUntilFirstUserAuthentication  True    True     mobile (501)  mobile (501)  1.2 KiB   2020-02-12 07:03:51 +0000  default.realm.lock
Regular           420  CompleteUntilFirstUserAuthentication  True    True     mobile (501)  mobile (501)  284.0 B   2020-05-29 18:15:23 +0000  userInfo.plist
Unknown           384  n/a                                   True    True     mobile (501)  mobile (501)  0.0 B     2020-02-12 07:03:51 +0000  default.realm.note

Readable: True  Writable: True

执行 ios plist cat 命令以检查 userInfo.plist 文件的内容。

...itudehacks.DVIAswiftv2.develop on (iPhone: 13.2.3) [usb] # ios plist cat userInfo.plist
{
        password = password123;
        username = userName;
}

搜索 SQLite 数据库

iOS 应用程序通常使用 SQLite 数据库来存储应用程序所需的数据。 测试人员应检查这些文件的数据保护值及其内容中是否包含敏感数据。 Objection 包含一个用于与 SQLite 数据库交互的模块。 它允许转储模式、它们的表和查询记录。

...itudehacks.DVIAswiftv2.develop on (iPhone: 13.2.3) [usb] # sqlite connect Model.sqlite
Caching local copy of database file...
Downloading /var/mobile/Containers/Data/Application/264C23B8-07B5-4B5D-8701-C020C301C151/Library/Application Support/Model.sqlite to /var/folders/4m/dsg0mq_17g39g473z0996r7m0000gq/T/tmpdr_7rvxi.sqlite
Streaming file from device...
Writing bytes to destination...
Successfully downloaded /var/mobile/Containers/Data/Application/264C23B8-07B5-4B5D-8701-C020C301C151/Library/Application Support/Model.sqlite to /var/folders/4m/dsg0mq_17g39g473z0996r7m0000gq/T/tmpdr_7rvxi.sqlite
Validating SQLite database format
Connected to SQLite database at: Model.sqlite

SQLite @ Model.sqlite > .tables
+--------------+
| name         |
+--------------+
| ZUSER        |
| Z_METADATA   |
| Z_MODELCACHE |
| Z_PRIMARYKEY |
+--------------+
Time: 0.013s

SQLite @ Model.sqlite > select * from Z_PRIMARYKEY
+-------+--------+---------+-------+
| Z_ENT | Z_NAME | Z_SUPER | Z_MAX |
+-------+--------+---------+-------+
| 1     | User   | 0       | 0     |
+-------+--------+---------+-------+
1 row in set
Time: 0.013s

搜索缓存数据库

默认情况下,NSURLSession 将数据(例如 HTTP 请求和响应)存储在 Cache.db 数据库中。 如果令牌、用户名或任何其他敏感信息已被缓存,则此数据库可能包含敏感数据。 要查找缓存的信息,请打开应用程序的数据目录 (/var/mobile/Containers/Data/Application/<UUID>) 并转到 /Library/Caches/<Bundle Identifier>。 WebKit 缓存也存储在 Cache.db 文件中。 Objection 可以使用命令 sqlite connect Cache.db 打开数据库并与之交互,因为它是一个普通的 SQLite 数据库。

建议禁用缓存此数据,因为它可能在请求或响应中包含敏感信息。 下面的列表显示了实现此目的的不同方法

  1. 建议在注销后删除缓存的响应。 这可以通过 Apple 提供的 removeAllCachedResponses 方法来完成。 您可以按如下方式调用此方法

URLCache.shared.removeAllCachedResponses()

此方法将从 Cache.db 文件中删除所有缓存的请求和响应。

  1. 如果您不需要使用 cookie 的优势,建议仅使用 URLSession 的 .ephemeral 配置属性,这将禁用保存 cookie 和缓存。

Apple 文档:

临时会话配置对象类似于默认会话配置(参见 default),只是相应的会话对象不会将缓存、凭据存储或任何与会话相关的数据存储到磁盘。 相反,与会话相关的数据存储在 RAM 中。 临时会话将数据写入磁盘的唯一时间是当您告诉它将 URL 的内容写入文件时。

  1. 也可以通过将缓存策略设置为 .notAllowed 来禁用缓存。 这将禁用以任何方式存储缓存,无论是在内存中还是在磁盘上。