iOS Pentesting

使用 Trickest 轻松构建和 自动化工作流程,由世界上 最先进 的社区工具提供支持。 立即获取访问权限:

支持 HackTricks

iOS 基础

测试环境

在此页面中,您可以找到有关 iOS 模拟器仿真器越狱的信息:

初步分析

基本 iOS 测试操作

在测试过程中 将建议进行几项操作(连接设备、读/写/上传/下载文件、使用一些工具...)。因此,如果您不知道如何执行这些操作,请 开始阅读页面

对于以下步骤 应用程序应已安装 在设备上,并且应已获得 IPA 文件。 阅读 基本 iOS 测试操作 页面以了解如何做到这一点。

基本静态分析

建议使用工具 MobSF 对 IPA 文件进行自动静态分析。

识别 二进制文件中存在的保护

  • PIE(位置无关可执行文件):启用时,应用程序每次启动时加载到随机内存地址,使其初始内存地址更难预测。

otool -hv <app-binary> | grep PIE   # 应该包含 PIE 标志
  • 栈金丝雀:为了验证栈的完整性,在调用函数之前将一个“金丝雀”值放置在栈上,并在函数结束时再次验证。

otool -I -v <app-binary> | grep stack_chk   # 应该包含符号:stack_chk_guard 和 stack_chk_fail
  • ARC(自动引用计数):防止常见的内存损坏缺陷

otool -I -v <app-binary> | grep objc_release   # 应该包含 _objc_release 符号
  • 加密二进制文件:二进制文件应被加密

otool -arch all -Vl <app-binary> | grep -A5 LC_ENCRYPT   # cryptid 应该为 1

识别敏感/不安全函数

  • 弱哈希算法

# 在 iOS 设备上
otool -Iv <app> | grep -w "_CC_MD5"
otool -Iv <app> | grep -w "_CC_SHA1"

# 在 Linux 上
grep -iER "_CC_MD5"
grep -iER "_CC_SHA1"
  • 不安全的随机函数

# 在 iOS 设备上
otool -Iv <app> | grep -w "_random"
otool -Iv <app> | grep -w "_srand"
otool -Iv <app> | grep -w "_rand"

# 在 Linux 上
grep -iER "_random"
grep -iER "_srand"
grep -iER "_rand"
  • 不安全的 ‘Malloc’ 函数

# 在 iOS 设备上
otool -Iv <app> | grep -w "_malloc"

# 在 Linux 上
grep -iER "_malloc"
  • 不安全和易受攻击的函数

# 在 iOS 设备上
otool -Iv <app> | grep -w "_gets"
otool -Iv <app> | grep -w "_memcpy"
otool -Iv <app> | grep -w "_strncpy"
otool -Iv <app> | grep -w "_strlen"
otool -Iv <app> | grep -w "_vsnprintf"
otool -Iv <app> | grep -w "_sscanf"
otool -Iv <app> | grep -w "_strtok"
otool -Iv <app> | grep -w "_alloca"
otool -Iv <app> | grep -w "_sprintf"
otool -Iv <app> | grep -w "_printf"
otool -Iv <app> | grep -w "_vsprintf"

# 在 Linux 上
grep -R "_gets"
grep -iER "_memcpy"
grep -iER "_strncpy"
grep -iER "_strlen"
grep -iER "_vsnprintf"
grep -iER "_sscanf"
grep -iER "_strtok"
grep -iER "_alloca"
grep -iER "_sprintf"
grep -iER "_printf"
grep -iER "_vsprintf"

基本动态分析

查看 MobSF 执行的动态分析。您需要浏览不同的视图并与之互动,但它将在执行其他操作时挂钩多个类,并在完成后准备报告。

列出已安装的应用程序

使用命令 frida-ps -Uai 确定已安装应用程序的 包标识符

$ frida-ps -Uai
PID  Name                 Identifier
----  -------------------  -----------------------------------------
6847  Calendar             com.apple.mobilecal
6815  Mail                 com.apple.mobilemail
-  App Store            com.apple.AppStore
-  Apple Store          com.apple.store.Jolly
-  Calculator           com.apple.calculator
-  Camera               com.apple.camera
-  iGoat-Swift          OWASP.iGoat-Swift

基本枚举与钩子

学习如何枚举应用程序的组件以及如何使用objection轻松钩住方法和类

IPA结构

IPA文件的结构本质上是一个压缩包。通过将其扩展名重命名为.zip,可以解压缩以揭示其内容。在此结构中,Bundle表示一个完全打包的应用程序,准备安装。在其中,您会找到一个名为<NAME>.app的目录,封装了应用程序的资源。

  • Info.plist:此文件包含应用程序的特定配置详细信息。

  • _CodeSignature/:此目录包含一个plist文件,包含签名,确保包中所有文件的完整性。

  • Assets.car:一个压缩档案,存储图标等资产文件。

  • Frameworks/:此文件夹包含应用程序的本地库,可能以.dylib.framework文件的形式存在。

  • PlugIns/:这可能包括应用程序的扩展,称为.appex文件,尽管它们并不总是存在。 * Core Data:用于保存应用程序的永久数据以供离线使用,缓存临时数据,并为您的应用在单个设备上添加撤消功能。要在单个iCloud帐户中的多个设备之间同步数据,Core Data会自动将您的架构镜像到CloudKit容器中。

  • PkgInfoPkgInfo文件是指定应用程序或包的类型和创建者代码的另一种方式。

  • en.lproj, fr.proj, Base.lproj:是包含特定语言资源的语言包,以及在不支持某种语言时的默认资源。

  • 安全性_CodeSignature/目录通过数字签名验证所有打包文件的完整性,在应用程序的安全性中发挥关键作用。

  • 资产管理Assets.car文件使用压缩有效管理图形资产,对于优化应用程序性能和减少整体大小至关重要。

  • 框架和插件:这些目录强调了iOS应用程序的模块化,允许开发人员包含可重用的代码库(Frameworks/)并扩展应用程序功能(PlugIns/)。

  • 本地化:该结构支持多种语言,通过包含特定语言包的资源,促进全球应用程序的覆盖。

Info.plist

Info.plist作为iOS应用程序的基石,以键值对的形式封装了关键配置数据。此文件不仅是应用程序的必需品,也是捆绑在内的应用扩展和框架的必需品。它以XML或二进制格式结构化,包含从应用权限到安全配置的关键信息。有关可用键的详细探索,可以参考Apple Developer Documentation

对于希望以更易于访问的格式处理此文件的用户,可以通过在macOS上使用plutil(在10.2及更高版本中原生可用)或在Linux上使用plistutil轻松实现XML转换。转换的命令如下:

  • 对于macOS

$ plutil -convert xml1 Info.plist
  • 对于Linux:

$ apt install libplist-utils
$ plistutil -i Info.plist -o Info_xml.plist

Info.plist文件可以透露的众多信息中,显著条目包括应用权限字符串(UsageDescription)、自定义URL方案(CFBundleURLTypes)和应用传输安全配置(NSAppTransportSecurity)。这些条目,以及其他如导出/导入的自定义文档类型(UTExportedTypeDeclarations / UTImportedTypeDeclarations),可以通过检查文件或使用简单的grep命令轻松找到:

$ grep -i <keyword> Info.plist

数据路径

在 iOS 环境中,目录专门用于 系统应用程序用户安装的应用程序。系统应用程序位于 /Applications 目录下,而用户安装的应用程序则放置在 /var/mobile/containers/Data/Application/ 下。这些应用程序被分配一个称为 128-bit UUID 的唯一标识符,使得手动定位应用程序文件夹的任务因目录名称的随机性而变得具有挑战性。

由于 iOS 中的应用程序必须进行沙箱处理,每个应用程序在 $HOME/Library/Containers 中也会有一个以应用程序的 CFBundleIdentifier 作为文件夹名称的文件夹。

然而,这两个文件夹(数据和容器文件夹)都有文件 .com.apple.mobile_container_manager.metadata.plist,该文件在键 MCMetadataIdentifier 中链接了这两个文件。

为了方便发现用户安装的应用程序的安装目录,objection 工具 提供了一个有用的命令 env。该命令显示了相关应用程序的详细目录信息。以下是如何使用此命令的示例:

OWASP.iGoat-Swift on (iPhone: 11.1.2) [usb] # env

Name               Path
-----------------  -------------------------------------------------------------------------------------------
BundlePath         /var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGoat-Swift.app
CachesDirectory    /var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693/Library/Caches
DocumentDirectory  /var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693/Documents
LibraryDirectory   /var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693/Library

或者,可以使用 find 命令在 /private/var/containers 中搜索应用程序名称:

find /private/var/containers -name "Progname*"

命令如 pslsof 也可以用来识别应用程序的进程和列出打开的文件,从而提供有关应用程序活动目录路径的见解:

ps -ef | grep -i <app-name>
lsof -p <pid> | grep -i "/containers" | head -n 1

Bundle directory:

  • AppName.app

  • 这是在IPA中看到的应用程序包,它包含了基本的应用程序数据、静态内容以及应用程序的编译二进制文件。

  • 该目录对用户可见,但用户无法写入

  • 此目录中的内容不被备份

  • 此文件夹的内容用于验证代码签名

Data directory:

  • Documents/

  • 包含所有用户生成的数据。应用程序最终用户发起此数据的创建。

  • 对用户可见,用户可以写入

  • 此目录中的内容被备份

  • 应用程序可以通过设置NSURLIsExcludedFromBackupKey来禁用路径。

  • Library/

  • 包含所有非用户特定文件,例如缓存偏好设置cookies和属性列表(plist)配置文件。

  • iOS应用程序通常使用Application SupportCaches子目录,但应用程序可以创建自定义子目录。

  • Library/Caches/

  • 包含半持久的缓存文件

  • 对用户不可见,用户无法写入

  • 此目录中的内容不被备份

  • 当应用程序未运行且存储空间不足时,操作系统可能会自动删除此目录的文件。

  • Library/Application Support/

  • 包含运行应用程序所需的持久****文件

  • 用户不可见,用户无法写入。

  • 此目录中的内容被备份

  • 应用程序可以通过设置NSURLIsExcludedFromBackupKey来禁用路径。

  • Library/Preferences/

  • 用于存储即使在应用程序重新启动后也能持久的属性。

  • 信息以未加密的形式保存在应用程序沙箱中的一个名为[BUNDLE_ID].plist的plist文件中。

  • 使用NSUserDefaults存储的所有键/值对都可以在此文件中找到。

  • tmp/

  • 使用此目录来写入临时文件,这些文件在应用程序启动之间不需要持久化。

  • 包含非持久的缓存文件。

  • 对用户不可见

  • 此目录中的内容不被备份。

  • 当应用程序未运行且存储空间不足时,操作系统可能会自动删除此目录的文件。

让我们更仔细地看看iGoat-Swift的应用程序包(.app)目录,位于包目录内(/var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGoat-Swift.app):

OWASP.iGoat-Swift on (iPhone: 11.1.2) [usb] # ls
NSFileType      Perms  NSFileProtection    ...  Name
------------  -------  ------------------  ...  --------------------------------------
Regular           420  None                ...  rutger.html
Regular           420  None                ...  mansi.html
Regular           420  None                ...  splash.html
Regular           420  None                ...  about.html

Regular           420  None                ...  LICENSE.txt
Regular           420  None                ...  Sentinel.txt
Regular           420  None                ...  README.txt

二进制逆向

<application-name>.app 文件夹内,您会找到一个名为 <application-name> 的二进制文件。这是将被 执行 的文件。您可以使用工具 otool 对二进制文件进行基本检查:

otool -Vh DVIA-v2 #Check some compilation attributes
magic  cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64    ARM64        ALL  0x00     EXECUTE    65       7112   NOUNDEFS DYLDLINK TWOLEVEL WEAK_DEFINES BINDS_TO_WEAK PIE

otool -L DVIA-v2 #Get third party libraries
DVIA-v2:
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.1)
/usr/lib/libsqlite3.dylib (compatibility version 9.0.0, current version 274.6.0)
/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.11)
@rpath/Bolts.framework/Bolts (compatibility version 1.0.0, current version 1.0.0)
[...]

检查应用是否加密

查看是否有任何输出:

otool -l <app-binary> | grep -A 4 LC_ENCRYPTION_INFO

反汇编二进制文件

反汇编文本段:

otool -tV DVIA-v2
DVIA-v2:
(__TEXT,__text) section
+[DDLog initialize]:
0000000100004ab8    sub    sp, sp, #0x60
0000000100004abc    stp    x29, x30, [sp, #0x50]   ; Latency: 6
0000000100004ac0    add    x29, sp, #0x50
0000000100004ac4    sub    x8, x29, #0x10
0000000100004ac8    mov    x9, #0x0
0000000100004acc    adrp    x10, 1098 ; 0x10044e000
0000000100004ad0    add    x10, x10, #0x268

要打印示例应用程序的 Objective-C 段,可以使用:

otool -oV DVIA-v2
DVIA-v2:
Contents of (__DATA,__objc_classlist) section
00000001003dd5b8 0x1004423d0 _OBJC_CLASS_$_DDLog
isa        0x1004423a8 _OBJC_METACLASS_$_DDLog
superclass 0x0 _OBJC_CLASS_$_NSObject
cache      0x0 __objc_empty_cache
vtable     0x0
data       0x1003de748
flags          0x80
instanceStart  8

为了获得更紧凑的 Objective-C 代码,您可以使用 class-dump:

class-dump some-app
//
//     Generated by class-dump 3.5 (64 bit).
//
//     class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2013 by Steve Nygard.
//

#pragma mark Named Structures

struct CGPoint {
double _field1;
double _field2;
};

struct CGRect {
struct CGPoint _field1;
struct CGSize _field2;
};

struct CGSize {
double _field1;
double _field2;
};

然而,反汇编二进制文件的最佳选项是:HopperIDA

使用 Trickest 轻松构建和 自动化工作流程,由世界上 最先进 的社区工具提供支持。 今天就获取访问权限:

数据存储

要了解 iOS 如何在设备中存储数据,请阅读此页面:

以下存储信息的地方应在 安装应用程序后立即 检查,检查应用程序的所有功能后,甚至在 从一个用户注销并登录到另一个用户后。 目标是找到应用程序的 未保护敏感信息(密码、令牌)、当前用户和之前登录用户的信息。

Plist

plist 文件是结构化的 XML 文件,包含键值对。这是一种存储持久数据的方式,因此有时您可能会在这些文件中找到 敏感信息。建议在安装应用程序后以及在密集使用后检查这些文件,以查看是否写入了新数据。

在 plist 文件中持久化数据的最常见方式是通过使用 NSUserDefaults。此 plist 文件保存在应用程序沙箱中的 Library/Preferences/<appBundleID>.plist

NSUserDefaults 类提供了与默认系统交互的编程接口。默认系统允许应用程序根据 用户偏好 自定义其行为。通过 NSUserDefaults 保存的数据可以在应用程序包中查看。此类将 数据 存储在 plist 文件 中,但旨在用于少量数据。

此数据不能再通过受信任的计算机直接访问,但可以通过执行 备份 进行访问。

您可以使用 objection 的 ios nsuserdefaults get转储 使用 NSUserDefaults 保存的信息。

要找到应用程序使用的所有 plist,您可以访问 /private/var/mobile/Containers/Data/Application/{APPID} 并运行:

find ./ -name "*.plist"

要将文件从 XML 或二进制 (bplist) 格式转换为 XML,可以根据您的操作系统使用各种方法:

对于 macOS 用户: 使用 plutil 命令。它是 macOS (10.2+) 中的内置工具,专为此目的设计:

$ plutil -convert xml1 Info.plist

对于Linux用户: 首先安装 libplist-utils,然后使用 plistutil 转换您的文件:

$ apt install libplist-utils
$ plistutil -i Info.plist -o Info_xml.plist

在 Objection 会话中: 对于分析移动应用程序,特定命令允许您直接转换 plist 文件:

ios plist cat /private/var/mobile/Containers/Data/Application/<Application-UUID>/Library/Preferences/com.some.package.app.plist

Core Data

Core Data 是一个用于管理应用程序中对象模型层的框架。Core Data 可以使用 SQLite 作为其持久存储,但该框架本身不是数据库。 CoreData 默认不加密其数据。然而,可以向 CoreData 添加额外的加密层。有关更多详细信息,请参见 GitHub Repo

您可以在路径 /private/var/mobile/Containers/Data/Application/{APPID}/Library/Application Support 中找到应用程序的 SQLite Core Data 信息。

如果您可以打开 SQLite 并访问敏感信息,那么您发现了一个配置错误。

Code from iGoat
-(void)storeDetails {
AppDelegate * appDelegate = (AppDelegate *)(UIApplication.sharedApplication.delegate);

NSManagedObjectContext *context =[appDelegate managedObjectContext];

User *user = [self fetchUser];
if (user) {
return;
}
user = [NSEntityDescription insertNewObjectForEntityForName:@"User"
inManagedObjectContext:context];
user.email = CoreDataEmail;
user.password = CoreDataPassword;
NSError *error;
if (![context save:&error]) {
NSLog(@"Error in saving data: %@", [error localizedDescription]);

}else{
NSLog(@"data stored in core data");
}
}

YapDatabase

YapDatabase 是一个基于 SQLite 的键值存储。 由于 Yap 数据库是 sqlite 数据库,您可以使用上一节中提供的命令找到它们。

其他 SQLite 数据库

应用程序通常会创建自己的 sqlite 数据库。它们可能在上面存储 敏感 数据,并且未加密。因此,检查应用程序目录中的每个数据库总是很有趣。因此,请前往保存数据的应用程序目录 (/private/var/mobile/Containers/Data/Application/{APPID})

find ./ -name "*.sqlite" -or -name "*.db"

Firebase 实时数据库

开发者可以通过 Firebase 实时数据库在 NoSQL 云托管数据库存储和同步数据。数据以 JSON 格式存储,并实时同步到所有连接的客户端。

您可以在这里找到如何检查配置错误的 Firebase 数据库:

Realm 数据库

Realm Objective-CRealm Swift 提供了一个强大的数据存储替代方案,这是 Apple 未提供的。默认情况下,它们 以未加密的方式存储数据,可以通过特定配置启用加密。

数据库位于:/private/var/mobile/Containers/Data/Application/{APPID}。要探索这些文件,可以使用以下命令:

iPhone:/private/var/mobile/Containers/Data/Application/A079DF84-726C-4AEA-A194-805B97B3684A/Documents root# ls
default.realm  default.realm.lock  default.realm.management/  default.realm.note|

$ find ./ -name "*.realm*"

为了查看这些数据库文件,推荐使用 Realm Studio 工具。

要在 Realm 数据库中实现加密,可以使用以下代码片段:

// Open the encrypted Realm file where getKey() is a method to obtain a key from the Keychain or a server
let config = Realm.Configuration(encryptionKey: getKey())
do {
let realm = try Realm(configuration: config)
// Use the Realm as normal
} catch let error as NSError {
// If the encryption key is wrong, `error` will say that it's an invalid database
fatalError("Error opening realm: \(error)")
}

Couchbase Lite 数据库

Couchbase Lite 被描述为一个 轻量级嵌入式 数据库引擎,遵循 文档导向 (NoSQL) 方法。它旨在原生支持 iOSmacOS,提供无缝同步数据的能力。

要识别设备上潜在的 Couchbase 数据库,应检查以下目录:

ls /private/var/mobile/Containers/Data/Application/{APPID}/Library/Application Support/

Cookies

iOS 将应用的 cookies 存储在每个应用文件夹中的 Library/Cookies/cookies.binarycookies 中。然而,开发者有时决定将它们保存在 keychain 中,因为提到的 cookie 文件可以在备份中访问

要检查 cookies 文件,您可以使用 这个 python 脚本 或使用 objection 的 ios cookies get 您还可以使用 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"
}
]

Cache

默认情况下,NSURLSession将数据存储在Cache.db数据库中,例如HTTP请求和响应。如果令牌、用户名或任何其他敏感信息被缓存,则该数据库可能包含敏感数据。要查找缓存的信息,请打开应用的数据目录(/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文件中删除所有缓存的请求和响应。 2. 如果您不需要使用cookie的优势,建议仅使用URLSession的.ephemeral配置属性,这将禁用保存cookie和缓存。

Apple文档:

一个短暂的会话配置对象类似于默认的会话配置(见默认),不同之处在于相应的会话对象不会将缓存、凭证存储或任何与会话相关的数据存储到磁盘上。相反,与会话相关的数据存储在RAM中。短暂会话写入数据到磁盘的唯一时间是当您告诉它将URL的内容写入文件时。 3. 通过将缓存策略设置为.notAllowed也可以禁用缓存。这将禁用以任何方式存储缓存,无论是在内存中还是在磁盘上。

Snapshots

每当您按下主屏幕按钮时,iOS 会拍摄当前屏幕的快照,以便能够以更平滑的方式过渡到应用程序。然而,如果当前屏幕上存在敏感 数据,它将被保存图像中(该图像在重启后仍然存在)。这些快照您也可以通过双击主屏幕在应用之间切换访问。

除非iPhone越狱,否则攻击者需要访问未被解锁设备才能查看这些屏幕截图。默认情况下,最后一个快照存储在应用的沙盒中,位于Library/Caches/Snapshots/Library/SplashBoard/Snapshots文件夹中(受信任的计算机无法从iOS 7.0访问文件系统)。

防止这种不良行为的一种方法是在使用ApplicationDidEnterBackground()函数拍摄快照之前,放置一个空白屏幕或删除敏感数据。

以下是设置默认屏幕截图的示例修复方法。

Swift:

private var backgroundImage: UIImageView?

func applicationDidEnterBackground(_ application: UIApplication) {
let myBanner = UIImageView(image: #imageLiteral(resourceName: "overlayImage"))
myBanner.frame = UIScreen.main.bounds
backgroundImage = myBanner
window?.addSubview(myBanner)
}

func applicationWillEnterForeground(_ application: UIApplication) {
backgroundImage?.removeFromSuperview()
}

Objective-C:

@property (UIImageView *)backgroundImage;

- (void)applicationDidEnterBackground:(UIApplication *)application {
UIImageView *myBanner = [[UIImageView alloc] initWithImage:@"overlayImage.png"];
self.backgroundImage = myBanner;
self.backgroundImage.bounds = UIScreen.mainScreen.bounds;
[self.window addSubview:myBanner];
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
[self.backgroundImage removeFromSuperview];
}

这会在应用程序进入后台时将背景图像设置为 overlayImage.png。它防止敏感数据泄漏,因为 overlayImage.png 将始终覆盖当前视图。

Keychain

要访问和管理 iOS 密钥链,可以使用像 Keychain-Dumper 这样的工具,适用于越狱设备。此外, Objection 提供了命令 ios keychain dump 用于类似目的。

存储凭据

NSURLCredential 类非常适合直接在密钥链中保存敏感信息,绕过 NSUserDefaults 或其他包装器的需要。要在登录后存储凭据,可以使用以下 Swift 代码:

NSURLCredential *credential;
credential = [NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistencePermanent];
[[NSURLCredentialStorage sharedCredentialStorage] setCredential:credential forProtectionSpace:self.loginProtectionSpace];

要提取这些存储的凭据,可以使用 Objection 的命令 ios nsurlcredentialstorage dump

自定义键盘和键盘缓存

从 iOS 8.0 开始,用户可以安装自定义键盘扩展,这些扩展可以在 设置 > 通用 > 键盘 > 键盘 下管理。虽然这些键盘提供了扩展功能,但它们存在记录按键和将数据传输到外部服务器的风险,尽管用户会被通知需要网络访问的键盘。应用程序可以并且应该限制在敏感信息输入时使用自定义键盘。

安全建议:

  • 建议禁用第三方键盘以增强安全性。

  • 注意默认 iOS 键盘的自动更正和自动建议功能,这可能会将敏感信息存储在位于 Library/Keyboard/{locale}-dynamic-text.dat/private/var/mobile/Library/Keyboard/dynamic-text.dat 的缓存文件中。这些缓存文件应定期检查以查找敏感数据。建议通过 设置 > 通用 > 重置 > 重置键盘字典 来重置键盘字典,以清除缓存数据。

  • 拦截网络流量可以揭示自定义键盘是否正在远程传输按键。

防止文本字段缓存

UITextInputTraits 协议 提供了管理自动更正和安全文本输入的属性,这对于防止敏感信息缓存至关重要。例如,可以通过禁用自动更正和启用安全文本输入来实现:

textObject.autocorrectionType = UITextAutocorrectionTypeNo;
textObject.secureTextEntry = YES;

此外,开发人员应确保文本字段,特别是用于输入敏感信息如密码和 PIN 的字段,通过将 autocorrectionType 设置为 UITextAutocorrectionTypeNosecureTextEntry 设置为 YES 来禁用缓存。