16、iOS 应用数据泄漏问题及解决策略

iOS 应用数据泄漏问题及解决策略

1. 自动补全机制与按键记录

iOS 的单词自动补全机制广为人知,它带来娱乐的同时也会产生有趣的拼写错误。然而,这个机制在无意中充当了按键记录器,会将用户输入的部分文本记录在一个基本为纯文本的文件中,以便未来补全使用。法医攻击者可以获取这个补全数据库。

对于密码字段,这种记录行为已被禁用,但应用中的其他表单可能会处理敏感数据。开发者需要在用户体验和安全性之间进行权衡。对于处理少量敏感数据的字段,如安全问题的答案,应通过设置 UITextField UITextView 对象的 autocorrectionType 属性为 UITextAutocorrectionTypeNo 来禁用自动补全行为。对于 UISearchBar 对象,这也是个好主意,因为搜索内容泄露到磁盘通常是不可取的。示例代码如下:

UITextField *sensitiveTextField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 25, 25)];
[sensitiveTextField setAutocorrectionType:UITextAutocorrectionTypeNo];

在 iOS 5.1 左右出现了一个 bug,即使禁用了自动补全、自动大写、拼写检查等功能,磁盘上的单词缓存仍会更新。目前有两种解决方法:
- “愚蠢”的方法 :使用 UITextView 并发送 setSecureTextEntry:YES 消息。 UITextView 类没有正确实现 UITextInputTraits 协议,文本不会像密码输入框那样被圆圈遮挡,但可以防止文本写入磁盘。示例代码如下:

-(BOOL)twiddleTextView:(UITextView *)textView {
    [textView setSecureTextEntry:YES];
}
  • “荒谬”的方法 :适用于 UITextView UITextField 对象,先开启再关闭 setSecureTextEntry 。示例代码如下:
-(BOOL)twiddleTextField:(UITextField *)textField {
    [textField setSecureTextEntry:YES];
    [textField setSecureTextEntry:NO];
}

不过, UISearchbar 没有正确实现该协议,不能使用此技巧。在进行这种开关操作之前,要确保应用运行的操作系统版本已经过测试。示例代码如下:

UITextField *sensitiveTextField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 25, 25)];
[sensitiveTextField setAutocorrectionType: UITextAutocorrectionTypeNo];
if ([[[UIDevice currentDevice] systemVersion] isEqual: @"8.1.4"]) {
    [sensitiveTextField setSecureTextEntry:YES];
    [sensitiveTextField setSecureTextEntry:NO];
}

为了验证应用是否意外泄露数据,可以检查模拟器或越狱设备上的 <device ID>/data/Library/Keyboard/dynamic-text.dat 文件。在 iOS 8 及更高版本中,键盘缓存中还会存储额外信息,位于 <device ID>/data/Library/Keyboard/en-dynamic.lm 目录下,包含 dynamic.dat lexicon.dat meta.dat tags.dat 四个文件。

2. 用户偏好的滥用

用户偏好通常包含敏感信息,但用户默认设置实际上是用于定义应用 API 的 URL 或其他非敏感偏好信息。开发者通过 NSUserDefaults API 或不太常用的 CFPreferences API 来操作偏好设置,但很多开发者可能不清楚这些数据在设备上的处理方式。这些文件的限制较为宽松,使用常见工具(如 iExplorer)可以轻松读取和操作用户偏好。

以下是一个来自 iGoat 项目的糟糕示例:

NSUserDefaults *credentials = [NSUserDefaults standardUserDefaults];
[credentials setObject:self.username.text forKey:@"username"];
[credentials setObject:self.password.text forKey:@"password"];
[credentials synchronize];

这是数据泄露的最坏情况,凭证以明文形式存储在应用的 plist 文件中。此外,开发者可能会使用 NSUserDefaults 存储用户不应控制的信息,如安全控制设置。为了保护用户,应尽可能让服务器来执行这些决策。在审核应用时,要检查每个 NSUserDefaults CFPreferences API 的使用情况,确保存储的数据合适,不应包含秘密信息或不希望用户更改的信息。

3. 快照中的敏感数据处理

iOS 在将应用发送到后台之前会对当前屏幕状态进行快照,以便在重新打开应用时生成动画。这可能导致敏感信息泄露到磁盘,即使用户并非有意将应用置于后台。例如,在输入敏感信息时接听电话,屏幕状态会被写入磁盘,直到被另一个快照覆盖。

一旦这些快照被写入磁盘,物理攻击者可以使用常见的取证工具轻松获取。可以在模拟器中观察文件的写入过程,只需暂停应用并打开 UIApplicationAutomaticSnapshot Default-Portrait.png 文件,该文件位于应用的 Library/Caches/Snapshots/com.mycompany.myapp 目录下。应用无法手动删除快照,但可以通过以下方法防止数据泄露:

3.1 屏幕清理策略

可以在截图实际发生之前更改屏幕状态,这需要在 applicationDidEnterBackground 委托方法中实现。该方法在应用即将暂停时被调用,开发者有几秒钟的时间完成任务。这个委托方法与 applicationWillResignActive applicationWillTerminate 事件不同,前者在应用暂时失去焦点时调用,后者在应用被强制终止或选择不进行后台操作时调用。iOS 应用的简化生命周期如下:
| 事件 | 说明 |
| ---- | ---- |
| didFinishLaunchingWithOptions | 应用启动完成 |
| applicationDidBecomeActive | 应用变为活跃状态 |
| applicationWillResignActive | 应用即将失去焦点 |
| applicationDidEnterBackground | 应用进入后台 |
| applicationWillTerminate | 应用即将终止 |

以下是几种屏幕清理的方法:
- 放置启动屏幕 :这是最简单和可靠的方法,在所有当前视图之上放置一个带有标志艺术的启动屏幕。示例代码如下:

- (void)applicationDidEnterBackground:(UIApplication *)application {
    application = [UIApplication sharedApplication];
    self.splash = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    [self.splash setImage:[UIImage imageNamed:@"myimage.png"]];
    [self.splash setUserInteractionEnabled:NO];
    [[application keyWindow] addSubview:splash];
}
  • 隐藏相关容器对象 :设置相关容器对象(如 UITextFields )的 hidden 属性,也可以隐藏整个 UIView
  • 执行动画 :进行一些自定义动画,如淡入淡出效果。示例代码如下:
- (void)fadeMe {
    [UIView animateWithDuration:0.2
                     animations:^{view.alpha = 0.0;}
                     completion:^(BOOL finished){[view removeFromSuperview];}
    ];
}
  • 模糊截图 :对当前屏幕状态进行截图并通过模糊算法处理,但要确保模糊效果足够强,攻击者无法逆转。

无论采用哪种混淆方法,都需要在 applicationDidBecomeActive applicationWillEnterForeground 委托方法中恢复更改。例如,要移除启动屏幕,可以在 applicationWillEnterForeground 方法中添加以下代码:

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

在完成之前,要通过在不同应用状态下多次暂停应用并监控 Library/Caches/Snapshots/com.mycompany.myapp 目录,确保清理技术有效,检查保存的 PNG 图像是否被启动屏幕完全遮挡。

3.2 屏幕清理策略的工作原理

iOS 应用的视图和窗口层次结构如下:

graph LR
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    A(UI elements):::process --> B(UIView):::process
    A --> C(UIWindow):::process
    A --> D(CALayer):::process

每个在屏幕上显示内容的应用都由一个层(默认是 CALayer )支持,层之上是 UIWindow 类的实例,它管理一个或多个 UIView 类的实例。 UIView 是分层的,一个视图可以有多个子视图以及按钮、文本字段等。iOS 应用通常只有一个 UIWindow ,但多个窗口也是可能的。默认情况下,窗口的 windowLevel 属性为 0.0,表示处于 UIWindowLevelNormal 级别。其他定义的级别包括 UIWindowlevelAlert UIWindowlevelStatusBar ,它们的优先级高于 UIWindowLevelNormal ,会显示在其他窗口之上。当前接收用户事件的窗口称为关键窗口,可以通过 UIApplication keyWindow 方法引用。

3.3 常见的清理错误

不了解 iOS 窗口和视图的开发者经常会错误地清理屏幕。常见的错误包括只隐藏关键窗口的根视图控制器,这会使根视图的子视图仍然可见;隐藏整个关键窗口也不是万无一失的,因为 UIAlertView 窗口会出现在其他内容之上并成为关键窗口,实际上只会隐藏警报。因此,建议开发者使用启动屏幕方法,对于某些用例,还有一种更简单、万无一失的方法:完全防止暂停。

3.4 防止暂停以避免快照

如果应用不需要暂停和恢复(即每次启动都希望有一个全新的开始),可以使用 Xcode plist 编辑器在 plist 文件中添加 “Application does not run in background” 并将其值设置为 YES ,也可以在 Info.plist 文件中设置 UIApplicationExitsOnSuspend YES 。这样应用会直接跳转到 applicationWillTerminate 事件,而不是停在 applicationDidEnterBackground 事件,从而避免截图。

4. 状态保存导致的泄漏

iOS 6 引入了状态保存的概念,用于在应用调用之间维护应用状态,即使应用在此期间被杀死。当触发状态保存时,每个可保存对象的 encodeRestorableStateWithCoder 委托方法会被调用,该方法包含如何将各种 UI 元素序列化到磁盘的指令。在重新启动应用时,会调用 decodeRestorableStateWithCoder 方法。这可能导致敏感信息从用户界面泄露到磁盘存储,因为文本字段和其他界面数据的内容会被存储在本地。

在检查新代码库时,可以通过在代码库中搜索 restorationIdentifier 来快速确定是否存在状态保存。如果使用了状态保存,在 .storyboard 文件中会找到类似以下的结果:

<viewController restorationIdentifier="viewController2" title="Second" id="3"
                customClass="StatePreservatorSecondViewController" sceneMemberID="viewController">
    <view key="view" contentMode="scaleToFill" id="17">
        <rect key="frame" x="0.0" y="20" width="320" height="499"/>
        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
        <subviews>
            <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill"
                      translatesAutoresizingMaskIntoConstraints="NO" id="Zl1-tO-jGB">
                <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
            </textView>
        </subviews>
    </view>
</viewController>

如果应用委托实现了 encodeRestorableStateWithCoder 方法,可以指定一个 encodeObject 方法来保存 UITextView .text 属性,以便后续恢复。示例代码如下:

-(void)encodeRestorableStateWithCoder:(NSCoder *)coder {
    [super encodeRestorableStateWithCoder:coder];
    [coder encodeObject:_messageBox.text forKey:@"messageBoxContents"];
}

在进行功能测试后,可以检查应用的 Library/Saved Application State/com.company.appname.savedState 目录下的 data.data 文件,该文件包含了分配了 restorationIdentifiers 的对象的序列化状态。通过检查该文件,可以确定用户界面中的敏感数据是否被编码。

5. 安全的状态保存

如果产品需要状态保存的用户体验和便利性,但需要在磁盘上安全存储数据,可以在将敏感对象内容传递给 encodeObject 方法之前对其进行加密。具体步骤如下:
1. 应用安装时,使用 secItemAdd 生成加密密钥并存储在钥匙串中。
2. 在 encodeRestorableStateWithCoder 方法中,从钥匙串中读取密钥并将其用作加密操作的密钥。
3. 将加密后的数据使用 NSCoder encodeObject 方法进行序列化。
4. 在 decodeRestorableStateWithCoder 方法中,执行相反的操作以恢复应用状态。

可以使用 SecureNSCoder 项目来帮助实现此功能。以下是使用该工具的示例项目步骤:
1. 在项目中包含 SecureArchiveDelegate SimpleKeychainWrapper 文件。
2. 在视图控制器的 .h 文件中包含 SecureArchiverDelegate.h 。示例代码如下:

#import <UIKit/UIKit.h>
#import "SecureArchiverDelegate.h"

@interface ViewController : UIViewController
// Some simple properties, adding one for the delegate
@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (weak, nonatomic) SecureArchiverDelegate *delegate;
@end
  1. 实现 initWithCoder 方法。示例代码如下:
- (id)initWithCoder:(NSKeyedUnarchiver *)coder {
    if (self = [super initWithCoder:coder]) {
        return self;
    }
    return nil;
}

通过以上方法,可以有效避免 iOS 应用中的数据泄露问题,保护用户的敏感信息安全。

iOS 应用数据泄漏问题及解决策略(续)

5. 安全的状态保存(续)

SecureNSCoder 项目为开发者提供了便利,它能够自动为应用生成密钥,将其存储在钥匙串中,并使用该密钥对程序状态进行编码和解码。下面详细介绍使用该工具的具体操作步骤:

5.1 项目文件引入

首先,要在项目里包含 SecureArchiveDelegate SimpleKeychainWrapper 文件。这两个文件是 SecureNSCoder 项目的重要组成部分,为后续的加密和解密操作提供了基础支持。

5.2 头文件包含

在视图控制器的 .h 文件中包含 SecureArchiverDelegate.h ,代码如下:

#import <UIKit/UIKit.h>
#import "SecureArchiverDelegate.h"

@interface ViewController : UIViewController
// Some simple properties, adding one for the delegate
@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (weak, nonatomic) SecureArchiverDelegate *delegate;
@end

这样做的目的是引入 SecureArchiverDelegate 类,以便在视图控制器中使用其提供的功能。

5.3 方法实现

实现 initWithCoder 方法,代码如下:

- (id)initWithCoder:(NSKeyedUnarchiver *)coder {
    if (self = [super initWithCoder:coder]) {
        return self;
    }
    return nil;
}

该方法在从归档中恢复对象时被调用,确保对象能够正确初始化。

6. 总结与建议

为了更清晰地展示 iOS 应用数据泄漏的问题及解决策略,下面以表格形式进行总结:
| 数据泄漏问题 | 具体表现 | 解决策略 |
| ---- | ---- | ---- |
| 自动补全机制与按键记录 | 自动补全机制充当按键记录器,记录用户输入文本,iOS 5.1 后存在即使禁用相关功能仍更新磁盘缓存的问题 | 对于少量敏感数据字段,禁用自动补全;使用 UITextView 并设置 setSecureTextEntry:YES 或对 UITextField 先开后关 setSecureTextEntry ;检查 dynamic-text.dat 等文件 |
| 用户偏好的滥用 | 开发者使用 NSUserDefaults CFPreferences API 存储敏感信息,文件限制宽松易被读取操作 | 审核 API 使用,确保存储非敏感数据,让服务器执行安全控制决策 |
| 快照中的敏感数据处理 | iOS 快照可能将敏感信息存储到磁盘,攻击者可获取 | 采用屏幕清理策略,如放置启动屏幕、隐藏容器对象、执行动画、模糊截图等;防止暂停以避免快照 |
| 状态保存导致的泄漏 | 状态保存机制可能将敏感 UI 数据序列化到磁盘 | 检查代码库中 restorationIdentifier ;对敏感数据加密后再进行状态保存,可使用 SecureNSCoder 项目 |

以下是一个简单的 mermaid 流程图,展示了处理数据泄漏问题的整体流程:

graph LR
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    A(发现数据泄漏风险):::process --> B(确定泄漏类型):::process
    B --> C{类型判断}:::process
    C -->|自动补全与按键记录| D(禁用自动补全,采用特殊方法):::process
    C -->|用户偏好滥用| E(审核 API 使用):::process
    C -->|快照敏感数据| F(屏幕清理或防止暂停):::process
    C -->|状态保存泄漏| G(加密敏感数据):::process
    D --> H(验证效果):::process
    E --> H
    F --> H
    G --> H

7. 注意事项

在实际开发过程中,还需要注意以下几点:
- 操作系统版本 :在使用一些特殊方法(如对 setSecureTextEntry 进行开关操作)时,要确保应用运行的操作系统版本已经过测试,因为某些 bug 可能在未来版本中得到修复。
- 测试验证 :无论是采用屏幕清理策略还是加密状态保存,都要进行充分的测试验证。例如,多次在不同应用状态下暂停应用,检查相关文件是否包含敏感信息。
- 代码规范 :在编写代码时,要遵循良好的代码规范,确保代码的可读性和可维护性。例如,在使用 NSUserDefaults CFPreferences API 时,要明确存储的数据类型和用途。

通过以上对 iOS 应用数据泄漏问题的分析和解决策略的介绍,开发者可以在开发过程中采取有效的措施,保护用户的敏感信息,提高应用的安全性。同时,不断关注操作系统的更新和安全漏洞的发现,及时调整开发策略,以应对不断变化的安全挑战。

内容概要:本文介绍了ENVI Deep Learning V1.0的操作教程,重点讲解了如何利用ENVI软件进行深度学习模型的训练与应用,以实现遥感图像中特定目标(如集装箱)的自动提取。教程涵盖了从数据准备、标签图像创建、模型初始化与训练,到执行分类及结果优化的完整流程,并介绍了精度评价与通过ENVI Modeler实现一键化建模的方法。系统基于TensorFlow框架,采用ENVINet5(U-Net变体)架构,支持通过点、线、面ROI或分类图生成标签数据,适用于多/高光谱影像的单一类别特征提取。; 适合人群:具备遥感图像处理基础,熟悉ENVI软件操作,从事地理信息、测绘、环境监测等相关领域的技术人员或研究人员,尤其是希望将深度学习技术应用于遥感目标识别的初学者与实践者。; 使用场景及目标:①在遥感影像中自动识别和提取特定地物目标(如车辆、建筑、道路、集装箱等);②掌握ENVI环境下深度学习模型的训练流程与关键参数设置(如Patch Size、Epochs、Class Weight等);③通过模型调优与结果反馈提升分类精度,实现高效自动化信息提取。; 阅读建议:建议结合实际遥感项目边学边练,重点关注标签数据制作、模型参数配置与结果后处理环节,充分利用ENVI Modeler进行自动化建模与参数优化,同时注意软硬件环境(特别是NVIDIA GPU)的配置要求以保障训练效率。
内容概要:本文系统阐述了企业新闻发稿在生成式引擎优化(GEO)时代下的全渠道策略与效果评估体系,涵盖当前企业传播面临的预算、资源、内容与效果评估四大挑战,并深入分析2025年新闻发稿行业五大趋势,包括AI驱动的智能化转型、精准化传播、首发内容价值提升、内容资产化及数据可视化。文章重点解析央媒、地方官媒、综合门户和自媒体四类媒体资源的特性、传播优势与发稿策略,提出基于内容适配性、时间节奏、话题设计的策略制定方法,并构建涵盖品牌价值、销售转化与GEO优化的多维评估框架。此外,结合“传声港”工具实操指南,提供AI智能投放、效果监测、自媒体管理与舆情应对的全流程解决方案,并针对科技、消费、B2B、区域品牌四大行业推出定制化发稿方案。; 适合人群:企业市场/公关负责人、品牌传播管理者、数字营销从业者及中小企业决策者,具备一定媒体传播经验并希望提升发稿效率与ROI的专业人士。; 使用场景及目标:①制定科学的新闻发稿策略,实现从“流量思维”向“价值思维”转型;②构建央媒定调、门户扩散、自媒体互动的立体化传播矩阵;③利用AI工具实现精准投放与GEO优化,提升品牌在AI搜索中的权威性与可见性;④通过数据驱动评估体系量化品牌影响力与销售转化效果。; 阅读建议:建议结合文中提供的实操清单、案例分析与工具指南进行系统学习,重点关注媒体适配性策略与GEO评估指标,在实际发稿中分阶段试点“AI+全渠道”组合策略,并定期复盘优化,以实现品牌传播的长期复利效应。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值