申明:本文非笔者原创,原文转载自:https://github.com/SecurityPaper/SecurityPaper-web/blob/master/_posts/2.SDL%E8%A7%84%E8%8C%83%E6%96%87%E6%A1%A3/2018-08-17-SDL-7-IOS%E5%AE%89%E5%85%A8%E7%BC%96%E7%A0%81%E8%A7%84%E8%8C%83.md
1.目的
为了使系统开发人员能够编写符合安全要求的代码,以降低代码安全漏洞,减少代码被利用的可能性,从而提升各系统安全水平,符合国家安全合规性要求,保障产品安全稳定运营及信息安全,特制定本规范。
2.引用规范
《信息安全技术移动智能终端个人信息保护技术要求》
《YD/T 1438-2006 数字移动台应用层软件功能要求和测试方法》
《YD/T 2307-2011 数字移动通信终端通用功能技术要求和测试方法》
《电子银行业务管理办法》
《电子银行安全评估指引》
《中国金融移动支付客户端技术规范》
《中国金融移动支付应用安全规范》
《移动互联网应用软件安全评估大纲》
《中国国家信息安全漏洞库CNNVD》
《OWASP》
3.适用范围
本规范适用产品的设计、开发及管理过程。其它研发机构可参考本管理规范;
iOS安全编码规范目标是为开发人员提供安全编码学习的参考资料,也可为iOS安全编码和iOS安全编码人工审计提供依据。
- 安全编码原则:
1)长远性和现实性相结合
既要兼顾银行的目前状况与长远发展等因素,又要放眼未来、统筹规划,具有可行性。
2)全面性和针对性相结合
既要具有全面性、着眼全局、不能遗漏,又要突出重点,建设方案和实施计划具有较强的针对性。
3)整体性和阶段性相结合
既要制定整体发展规划、安全建设蓝图等战略性指导和安全策略文档,又要制定出体系实施的阶段性目标,分期分批实施。
4)先进性和实用性相结合
在信息安全战略和策略、目标和要求、规定和制度、技术、人员和知识等各方面,既要有先进性(例如虚拟化技术),又要有实用性。
5)开放性和可扩展性相结合
应采用最新且成熟的体系框架,保证具有开放性和可扩展性。
6)完整性和经济性相结合
既要考虑采用的产品和技术在整体上具有完整性和一致性,又要尽量保护银行已有的软硬件投资,使得总体上具有更好经济性。
4.安全编码规则
本篇参考OWASP Mobile Top 10 2016分别从平台使用不当、不安全的数据储存、不安全的通信、不安全的认证、加密不足、不安全的授权、客户端的代码质量、逆向工程、多余的功能、其他安全问题9个方面规定了如何在代码方面防范软件安全问题。这些问题一旦出现将会形成软件安全漏洞如密钥使用不当、件最小化组件暴露等造成生产安全事故,可能带来经济、客户、声誉等方面重大的损失。
4.1.平台使用不当
4.1.1.定义
该类别包括平台功能的滥用或未使用平台的安全控制,它主要包括了对X-code工具编码时对工具的警示与提示的重视。
4.1.2.风险
移动平台提供许多不同的服务,从身份验证,到安全的数据存储,再到安全的网络通信。没有正确地使用平台的相关功能,因此,可能造成数据暴露、连接到不受信的主机、或实现欺诈付款。移动应用程序的隐私和权限也是平台的领域。因此,未能恰当使用平台的功能,可能会最终暴露用户隐私。
4.1.3.防范方法
4.1.3.1.X-code警告与提示
【规范要求】
编码时应关注X-code编译器中的警告与提示。
【详细说明】
通过X-code编译器生成的警告与提示可帮助开发者减少代码的复杂性、确保正确的语法,警告与提示中还提供一些修改的建议:如符号的问题或格式字符串漏洞等。
【代码示例】
反例:NSInteger和NSUInteger类型比较时,若传入一个负数则条件判断恒成立;如下,用户传入desired参数为-1时,else将不会执行:
- (void) validate:(NSArray *) someTribbles withValue:(NSInteger) desired {
if (desired > [someTribbles count]) {
NSLog(@"执行一段重要的逻辑...");
} else {
NSLog(@"其它操作");
}
}
正例:NSUInteger和NSUInteger类型比较时,则任何情况下都恒成立:
- (void) validate:(NSArray *) someTribbles withValue:( NSUInteger) desired {
if (desired > [someTribbles count]) {
NSLog(@"执行一段重要的逻辑...");
} else {
NSLog(@"其它操作");
}
}
4.2.不安全的数据储存
4.2.1.定义
这个类别包括“不安全的数据存储”和“意外造成的数据泄漏”。 不安全的数据存储,包括但不限于以下方面:
- SQL数据库;
- 日志文件;
- XML 数据中存储OU名单文件;
- 二进制数据存储;
- Cookie 存储;
- SD卡;
- Cloud 同步。
意外造成的数据泄漏,包括但不限于以下方面:
- 操作系统;
- 开发框架;
- 编译器环境;
- 新硬件设备。
在移动开发过程中,常见的没有记录或记录在案的内部处理方式,包括:
- 操作系统缓存数据、图像、按键、日志和缓冲区的方式;
- 开发框架缓存数据、图像、按键、日志和缓冲区的方式;
- 数据、分析、社交或实现框架缓存数据、图像、按键、日志和缓冲区的方式与次数。
它对你的移动应用程序、操作系统、平台和框架进行威胁建模分析是非常重要的,这样可以对应用程序处理的信息资产有所理解,并且可以知道 API 是如何处理这些资产的。关键是看它们如何处理以下类型的功能:
- URL缓存(包括请求与响应);
- 键盘按键缓存;
- 复制、粘贴缓冲区缓存;
- 应用程序后台处理;
- 日志;
- HTML5 数据存储;
- 浏览器cookie对象;
- 发往第三方的数据分析。
4.2.2.风险
这可能会导致数据丢失,最好的情况是只丢失一个用户的数据,而最坏的情况 是丢失许多用户的数据。它也可能导致以下技术影响:通过移动设备中所含的恶意软件、被篡改的应用程序或调查分析工具,提取应用程序中的敏感信息。 对业务影响的性质,高度依赖于被盗信息的性质。不安全的数据可能会导致以下业务影响:
- 身份信息被盗;
- 隐私泄露;
- 诈骗;
- 名誉受损;
- 违反外部的政策要求(如:PCI);
- 材料丢失。
4.2.3.防范方法
4.2.3.1.存储安全
- 【规范要求】
1)敏感数据或文件,必须加密存储; 2)禁止密码被UIWebView明文存储。
- 【详细说明】
敏感数据未进行加密存储货密码被UIWebView明文存储,存在被攻击者利用的风险,需要进行加密处理。
4.2.3.2.NSURL缓存需及时清除
- 【规范要求】
使用NSURL层传输数据时,需要配置安全的缓存策略,以保证缓存数据的安全。
- 【详细说明】
NSURL缓存存在泄漏敏感数据的风险。在开发过程中需要配置安全的缓存策略,如:
-
- 在程序退出时清空缓存;
-
- 实现NSURLConnectionDataDelegate协议,对敏感数据的缓存进行过滤;
-
- 在使用NSURLSession时敏感的数据采用ephemeralSessionConfiguration配置,与默认配置相比,这个配置不会将缓存、cookie等存在本地,只会存储在内存里,所以当程序退出时,所有的数据都会消失。
-
【代码示例】
清空缓存的方法如下:
- (void)clearNSURLCache
{
//清空内存缓存
[[NSURLCache sharedURLCache] removeAllCachedResponses];
//清空磁盘缓存
NSURLCache *urlCache = [[NSURLCache alloc] init];
[urlCache setDiskCapacity:0];
[NSURLCache setSharedURLCache:urlCache];
}
过滤敏感数据的缓存代码如下:
-(NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
NSCachedURLResponse *newCachedResponse=cachedResponse;
if ([[[[cachedResponse response] URL] scheme] isEqual:@"https"]) {
newCachedResponse=nil;
}
return newCachedResponse;
}
NSURLSession配置ephemeralSessionConfiguration代码如下:
NSURLSessionConfiguration *config = [NSURLSessionConfiguration ephemeralSessionConfiguration];
4.2.3.3.键盘缓存需及时清除
【规范要求】
敏感数据输入过程需要禁止键盘缓存功能,如:银行卡号、密码、手机号等用户的隐私信息。
【详细说明】
iOS中使用的键盘类会导致数据被自动存储到数据库中,在应用程序中点击每一个键盘键时,都将会被明文存储。以下场景除外:
- 密码框中的数据不会被缓存;
- 全部由数字组成的字符串不会被缓存;
- 禁用文本框的自动更正可以防止数据被缓存;
- 太短的字符输入数据不会被缓存;
- 自定义布局的键盘不会被缓存。
【代码示例】
禁用文本框自动更正(缓存)的代码:
UITextField *sensitiveTextField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 25, 25)];
[sensitiveTextField setAutocorrectionType:UITextAutocorrectionTypeNo];
4.2.3.4.用户的控制信息
【规范要求】
控制类信息禁止通过NSUserDefaults进行储存,建议使用数据库进行储存。
【详细说明】
常见的用户控制类信息如:
- 决定用户是否可以下载资源存储到本地;
- 在使用时是否输入PIN码作为安全控制。
4.3.不安全的通信
4.3.1.定义
本类风险涵盖了从A点到B点之间采用不安全的方式进行数据通讯。数据通讯组成包含了移动设备之间的通信、应用程序至服务器之间的通信、或者移动设备至其他设备之间的通信。这种风险包括移动设备可能使用的所有通信技术:TCP/IP、WiFi、蓝牙或LE蓝牙、NFC、音频、红外、GSM、3G、短信等。所有有关TLS通信、NFC、蓝牙和WiFi 的问题,都包含在这部分。
4.3.2.风险
不安全的通信的一般风险存在在于数据的完整性、数据的保密性和数据来源的完整性等方面。如果数据在传递过程中是可以改变的,且在信息传递过程中没有检测到发生的变化(如:通过中间人攻击),那么这就是这种风险的一个很好的例子。如果保密数据可以被暴露、获取、或通过在通信过程中观察(如:窃听)而得出通讯内容、或通过在通信过程中进行录制并进行后续攻击(如:离线攻击),这也是不安全的通信问题。没有正确安装和验证TLS连接(如:证书的检验、弱密码、其他TLS配置问题)都属于“不安全的通信”问题。
4.3.3 防范方法
4.3.3.1传输安全
【规范要求】
1)禁止明文传输敏感数据;
2)涉及支付,客户端和服务端通信强制采用https加密;
3)移动应用和服务器端SSL通信必须严格检查服务器端证书有效性,避免手机银行用户访问钓鱼网站泄露敏感信息。
【详细说明】
对客户端与服务端之间的数据传输中间过程进行加密,防止网络世界当中其他节点对数据的窃听。
4.4.不安全的认证
4.4.1 定义
这个类别包括对终端用户身份验证或会话管理的建议。这可以包括:
- 当接收请求时,没有对用户进行身份识别;
- 当接收请求时,没有保持对用户身份的确认;
- 会话管理中的漏洞。
身份验证问题是指处置与身份验证有关的隐私问题方法是否合理。例如:如果一个移动应用程序使用特定设备的数据,如:IMEI、蓝牙MAC地址、或其他作为用户身份验证的硬件标识符,可以为应用程序开发人员或拥有者建立对隐私保护的期望。如果使用不安全的信道进行身份验证而导致欺骗、重放或其他针对身份验证的攻击,那么这也属于这个类别的范畴。在移动应用程序中不恰当的存储密码,属于“不安全的数据存储”问题;以明文传输密码,则属于“不安全的通信”问题。例如:如果攻击者通过观察一个用户在客户端中的注册行为,而洞察到用户的数据,并将其用于随后的注册行为中,这就是属于本类别的一个身份验证问题。
4.4.2风险
一个身份验证的常见风险是向未识别身份的用户暴露数据或提供服务。匿名用户可以调用Web服务(如:计划旅行路线、将项目放入购物篮、产生图像),而Web服务的本意是只允许已注册的或已识别身份的用户执行该操作。
4.4.3.防范方法
4.4.3.1.HTTPS证书验证
【规范要求】
进行网络通讯时使用HTTPS协议需要进行双向认证。
【详细说明】
移动应用程序和服务端成功连接并执行一个TLS 握手协议建立安全通道。然而,移动应用程序没有检查服务器提供的证书,且移动应用程序无条件地接受由服务器提供给它的任何证书。这破坏了移动应用程序和终端之间的相互认证能力。移动应用程序通过TLS代理容易受到中间人攻击。
【代码示例】
安全规范类验证证书文件和域名信息的代码如下:
NSURL *httpsURL = [NSURL URLWithString:@"https://www.google.com"];
self.connection = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:httpsURL] delegate:self];
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
NSString *user = @"user";
NSString *pass = @"pass";
//验证域名
if ([[challenge protectionSpace] receivesCredentialSecurely] == YES &&
[[[challenge protectionSpace] host] isEqualToString:@"myhost.com"]) {
NSURLCredential *credential = [NSURLCredential credentialWithUser:user password
:pass persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
}
//1)获取trust object
SecTrustRef trust = challenge.protectionSpace.serverTrust;
SecTrustResultType result;
//2)SecTrustEvaluate对trust进行验证
OSStatus status = SecTrustEvaluate(trust, &result);
if (status == errSecSuccess &&
(result == kSecTrustResultProceed ||
result == kSecTrustResultUnspecified)) {
//3)验证成功,生成NSURLCredential凭证cred,告知challenge的sender使用这个凭证来继续连接
NSURLCredential *cred = [NSURLCredential credentialForTrust:trust];
[challenge.sender useCredential:cred forAuthenticationChallenge:challenge];
} else {
//4)验证失败,取消这次验证流程
[challenge.sender cancelAuthenticationChallenge:challenge];
}
}
4.4.3.2.鉴别合法用户
【规范要求】
在支付、登录等核心业务中,除了分配唯一的ID,建议同时采用其他方法对用户的合法性进行鉴别。
【详细说明】
至少采样下列方式的一种方法用于鉴别合法用户:
- 口令;
- 短信认证;
- 令牌设备;
- 生物特征。
4.4.3.3.多样化接入认证方式
【规范要求】
除用户密码外,必须加上其他认证方式。
【详细说明】
移动终端的认证方式有本地认证(用户名,密码)、动态令牌(一次性密码认证令牌),手机SIM卡绑定、SD证书认证、短信认证等方式,如下:
- 动态令牌认证:
增配动态口令RSA令牌(类似网络银行的U盾,即在静态用户名和密码外增加一重安全性保障),实现更高级别的接入安全。动态令牌服务端基于时间周期与客户端动态令牌进行同步,每隔60秒产生一个新的口令,口令根据特定算法生成不可预测的随机数字组合,且每个口令只能使用一次。
- 手机令牌认证:
手机令牌认证原理类似动态令牌认证。手机动态令牌服务端在手机上安装手机令牌客户端软件,基于事件触发方式,与服务器保持密码同步。由于其高安全性和易携带性,手机令牌认证作为主流认证方式。
- 手机SIM卡绑定:
读取SIM卡特定信息,生成唯一特征码,在后台设定用户SIM绑定后,用户第一次登录前台,会自动上传唯一特征码,完成SIM卡绑定。
- 手机硬件特征码绑定:
读取手机硬件信息,生成唯一特征码,在后台设定用户手机硬件特征码绑定后,用户第一次登录前台,会自动上传唯一特征码,完成手机硬件信息绑定。
- 证书认证:
支持SD卡证书认证。结合税务系统身份认证系统平台,数字证书中含有密钥对(公钥和私钥)所有者的识别信息,通过验证识别信息的真伪实现对证书持有者身份的认证。 手机用户第一次以静态用户名密码方式登录,进行证书下载,下载证书安装后,即可由启用证书认证。如果是证书和静态用户名密码绑定用户,用户卸载终端或者更换设备后,须通知管理员清除其证书下载状态,才能再次下载证书进行认证。
- 短信认证:
与短信平台结合认证。管理员在后台设置手机短信认证功能,为每个用户绑定手机号码,用户在进行移动办公登录时,首先会收到系统发送的短信验证码,才能在移动平台上进行相应的登录操作。
4.4.3.4.图形认证码
【规范要求】
图形认证码应满足:
- 由数字和字母等字符混合组成;
- 随机产生;
- 采取图片底纹干扰、颜色变换、设置非连续性及旋转图片字体、变异字体显示样式等有效方式,防范恶意代码自动识别图片上的信息;
- 具有使用时间限制并仅能使用一次;
- 图形认证码应由服务器生成,客户端源文件中不应包含图形验证码文本内容。
【详细说明】
添加图片验证码,防止暴力破解。
4.5.加密不足
4.5.1.定义
代码中使用加密技术对敏感信息进行加密。然而,加密技术在某种程度上是不足的。需要注意的是,任何与TLS或SSL有关的内容需调整至M3中。此外,如果应用程序在它使用加密技术时而没有成功使用,该类问题可能属M2。本类别是在尝试使用加密技术同时保证成功使用。
4.5.2.风险
使用加密技术保护的数据可能会被暴露。典型的结果为:数据的保密性得到了保护或数据的完整性得到了保护。保密性风险可能包括对数据的离线暴力破解攻击,或者对加密数据的推理攻击。这种风险意味着攻击者获得了受保护的信息。完整性风险可能包括重放攻击(如果一个密码签名可以伪造的话)。如果签名可以被伪造,可能会得到不安全的代码。可猜测的或可预测的加密令牌则可能导致虚假的交易。
4.5.3.防范方法
4.5.3.1.加密算法使用规范
【规范要求】
1)不建议将密码加密等敏感信息使用的算法类型包括:
- MD2
- MD4
- MD5
- SHA-1
- PIPEMD
2)安全规范建议使用算法类型包括:
- SHA-256
- SHA-3
【详细说明】
使用低强度的密码比不进行任何加密更危险。对于用户来说,安全感与密码的强度无关,而只是由“信息已经被加密了”这一事实产生的,而这通常会导致用户在处理一些机密信息的时候麻痹大意。
4.5.3.2.禁止硬编码形式存储密钥
【规范要求】
禁止以硬编码形式存储密钥。
【详细说明】
开发者将密钥以硬编码的方式存储在代码、文件中,这样做会引起很大风险。信息安全的基础在于密码学,而常用的密码学算法都是公开的,加密内容的机密性是依赖密钥的保密提起下,密钥如果泄露,对于对称密码算法,根据使用的密钥算法和加密后的密文,很容易得到加密前的明文;对于非对称密码算法或者签名算法,根据密钥和要加密的明文,很容易获得计算出签名值,从而伪造签名。
4.6.不安全的授权
4.6.1.定义
这个类别包括任何失败的授权行为(例如:在客户端的授权决策、强迫浏览等)。它有别于身份验证问题(例如:设备注册、用户标识等)。如果应用程序在需要的时候没有验证用户的身份(例如:当访问要求需经过身份验证和授予权限时,授予匿名用户访问某些资源或服务的权限),那就是一起身份验证失败事件,而不仅仅是授权失败事件。
4.6.2.风险
典型风险涉及对未经授权的用户授予访问权限。用户可执行他们本不能执行的创建、读取、更新、删除(CRUD)操作。他们可以调用服务,或使用凭据本没有授予他们的服务。
4.6.3.防范方法
4.6.3.1.分配唯一的ID
【规范要求】
建议程序中获取UUID并将它储存在钥匙串中作为设备的唯一ID。
【详细说明】
为每一个具有访问权限的用户分配唯一的设备ID,并与用户信息绑定,以保证对于关键数据和支付软件的操作能够追溯到已知的、被授权的用户,其中对唯一ID的重要性分析如下:
1)存在安全隐患的数据储存方案如下:
2)进行安全规范类加密的原理如下:
【代码示例】
程序中获取UUID储存钥匙串的代码:
+ (NSString*) getUUIDString
{
//从钥匙串读数据
NSMutableDictionary *usernamepasswordKVPair = (NSMutableDictionary *)[self load:@"cn.ijaimi.IJMCrashInfo.UUID"];
NSString *uuid = [usernamepasswordKVPair objectForKey:@"IJMCrashInfo_UUID"];
if (uuid == nil || [uuid isEqualToString:@""]) {
//写数据到钥匙串
CFUUIDRef uuidObj = CFUUIDCreate(nil);
NSString *uuidString = (__bridge_transfer NSString*)CFUUIDCreateString(nil, uuidObj);
CFRelease(uuidObj);
NSMutableDictionary *usernamepasswordKVPairs = [NSMutableDictionary dictionary];
[usernamepasswordKVPairs setObject:uuidString forKey:@"IJMCrashInfo_UUID"];
[self save:@"cn.ijaimi.IJMCrashInfo.UUID" data:usernamepasswordKVPairs];
uuid = uuidString;
}
return uuid;
}
4.6.3.2.授权与访问控制
【规范要求】
1)服务端对客户端下载的资源进行访问授权控制; 2)服务端限制单位时间内事务请求数量; 3)服务端不允许客户端同一个账号同时在多个设备上成功登录客户端; 4)服务端限制客户端登录尝试次数; 5)客户端登录失败提示内容统一。
【详细说明】
移动应用程序根据用户的等级提供适当的菜单和选项,这是正常的。但是,如果服务器在没有验证用户的权限或等级的情况下响应和执行任意请求,毫无保留的信任移动端程序代码,并根据用户的权限级别生成相应的请求,这就是一个典型的不安全授权。
4.7.客户端代码质量
4.7.1.定义
这个类别包括移动客户端代码级别开发的全部问题。不同于服务器端的编码错误。本类别包括例如缓冲区溢出、字符串格式漏洞以及其他不同类型的代码级错误,而这些错误的解决方法是存在于移动设备中运行的某些代码。
4.7.2.风险
有害代码可以允许攻击者利用业务逻辑,或绕过设备上的安全控制。代码级的错误会以特殊的方式暴露敏感数据。
4.7.3.防范方法
4.7.3.1 防止字符串格式化漏洞攻击
【规范要求】
代码中不能省略格式化参数。
【详细说明】
省略格式化参数容易产生格式化字符串漏洞,例如:NSString *userText = @"%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x"
,”%x”会返回内存中对象的地址,存在运行过程中被篡改的风险。
【代码示例】
反例:”%x”会返回内存中对象的地址,存在运行过程中被篡改的风险:
NSString *userText = @"%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x";
NSLog(userText);
NSString *myStuff = @"Evil things %x%x%x%x%x";
myStuff = [myStuff stringByAppendingString:myStuff];
NSLog(@"myStuff = %@", myStuff);
正例:正确使用格式化参数的代码:
NSString *userText = [NSString stringWithFormat:@"%x%x", 0x0001, 0x0002];
NSLog(@"%@", userText);
4.7.3.2.防止缓冲区溢出攻击
【规范要求】
避免使用strcpy和strcat方法,改用 strlcpy和strlcat方法,如果必须使用strcpy时需要进行strnlen验证。
【详细说明】
缓冲区溢出造成的危害比较多样,轻微的结果是程序直接崩溃,比较严重的结果是错误的写入覆盖了原本的敏感数据,造成数据的丢失;最严重的莫过于执行恶意代码,因为数据写入越界,恶意代码可以将原先正常的函数返回地址修改为自己的代码地址,从而获得整个软件的执行权。
【代码示例】
在使用strcpy方法应加上if进行strnlen验证,会防止导致缓冲区溢出:
#include <string.h>
uid_t check_user(char *provided_uname, char *provided_pw) { char password[32]; char username[32]; if (strnlen(provided_pw, 32) < strnlen(password, 32)) { strcpy(password, provided_pw); } if (strnlen(provided_uname, 32) < strnlen(username, 32)) { strcpy(username, provided_uname); } struct *password pw = getpwnam(username); if (0 != strcmp(crypt(password), pw->pw_passwd)) return -1; return pw->uid; }
避免使用strcpy和strcat方法,改用strlcpy和strlcat方法:
void copythings(char *things) {
char buf[32];
length = strlcpy(buf, things, sizeof(buf)); }
4.7.3.3.验证发送URL Schemes请求的应用的真实性。
【规范要求】
应用通过URL Scheme方式启动时需要对URL参数进行验证。
【详细说明】
URL Scheme方式启动时应对URL进行验证来防止注入攻击和APP恶意调用。
【代码示例】
1)application:didFinishLaunchingWithOptions:中验证URL代码为:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if ([launchOptions objectForKey:UIApplicationLaunchOptionsURLKey] != nil) {
NSURL *url = (NSURL *)[launchOptions valueForKey:UIApplicationLaunchOptionsURLKey];
if ([url query] != nil) {
NSString *theQuery = [[url query] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
if (![self isValidQuery:theQuery]) {
return NO;
}
}
}
return YES;
}
2)application:openURL:sourceApplication:annotation:中验证URL代码为:
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options
{
if ([sourceApplication isEqualToString:@"com.apple.mobilesafari"]) {
//不希望执行的URL请求 return NO; } else { NSString *theQuery = [[url query] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSArray *chunks = [theQuery componentsSeparatedByString:@"&"]; for (NSString *chunk in chunks) { NSArray *keyval = [chunk componentsSeparatedByString:@"="]; NSString *key = [keyval objectAtIndex:0]; NSString *value = [keyval objectAtIndex:1]; //其它操作... return YES; } } }
4.7.3.4.网络请求的加载与过滤
【规范要求】
UIWebView网络请求中应加入黑名单和白名单的配置。
【详细说明】
UIWebView的webView:shouldStartLoadWithRequest:方法用于加载指定域名的请求,过滤非HTTPS请求和未知域名。
【代码示例】
webView:shouldStartLoadWithRequest:方法的加载与过滤代码实现:
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *url = [request URL];
if ([[url scheme] isEqualToString:@"https"]) {
if ([url host] != nil) {
NSString *goodHost = @"ipacheck.ijiami.cn"; if ([[url host] isEqualToString:goodHost]) { return YES; } } } return NO; }
4.7.3.5.禁止加密算法及密钥的明文存储
【规范要求】
禁止UIWebView中实现加密算法及密钥的明文存储。
【详细说明】
建议在Objective-C实现加密算法的过程并在JavaScript中进行调用来实现对UIWebView的敏感数据加密。
【代码示例】
1)Objective-C中实现的加密算法代码:
SContext *context = [[JSContext alloc] init];
context[@"shasum"] = ^(NSString *data, NSString *salt) {
const char *cSalt = [salt cStringUsingEncoding:NSUTF8StringEncoding];
const char *cData = [data cStringUsingEncoding:NSUTF8StringEncoding]; unsigned char digest[CC_SHA256_DIGEST_LENGTH]; CCHmac(kCCHmacAlgSHA256, cSalt, strlen(cSalt), cData, strlen(cData),digest); NSMutableString *hash = [NSMutableString stringWithCapacity: CC_SHA256_DIGEST_LENGTH]; for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) { [hash appendFormat:@"%02x", digest[i]]; } return hash; };
2)JavaScript中调用加密算法代码:
var password = document.getElementbyId('password'); var salt = document.getElementbyId('salt'); var pwhash = shasum(password, salt);
4.7.3.6.WKWebView控件
【规范要求】
在iOS8.0以上的版本中,编码时尽量使用更安全的WKWebView控件取代UIWebView控件。
【详细说明】
WKWebViews修复了UIWebView中存在的很多问题,相比UIWebView的安全性更强,执行效率更高。
【代码示例】
使用WKWebView控件例子:
CGRect webFrame = CGRectMake(0, 0, width, height);
WKWebViewConfiguration *conf = [[WKWebViewConfiguration alloc] init];
WKWebView *webView = [[WKWebView alloc] initWithFrame:webFrame configuration:conf];
NSURL *url = [NSURL URLWithString:@"http://www.nostarch.com"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [webView loadRequest:request]; <script type="text/javascript"> var exec = cordova.require('cordova/exec'); function callback(msg) { console.log(msg); } exec(callback, callback, "File", "readAsText", ["/private/var/mobile/Library/Preferences/com.apple.MobileSMS.plist", "UTF-8", 0, 2048]); </script>
4.8.逆向工程
4.8.1.定义
本类别包含对核心二进制代码的分析,以确定它的源代码、库文件、算法和其他资产是否安全。比如:使用IDA Pro、Hopper、otool 和其他二进制检验工具对文件进行逆向,使攻击者能洞察到应用程序内部的工作原理。这可用于在应用程序中发现漏洞,并可揭露有关后端服务器、加密算法、密钥、知识产权等信息。
4.8.2.风险
通过逆向工程,攻击者可以枚举或绕过业务逻辑、绕过安全控制、促进源代码盗用和篡改代码。如果源代码不是模糊的,那么就变得很容易让攻击者或对手复制应用程序。攻击者可以重新打包应用程序,并通过各种方式发布给公众。这涉及到一个风险较高的业务风险:收入损失、品牌损害、或假冒的应用程序副本泛滥。这些假冒的副本也可以用于网络钓鱼或凭据盗窃。
4.8.3.防范方法
4.8.3.1.系统第三方输入法
【规范要求】
敏感数据录入时禁止使用第三方输入法。
【详细说明】
第三方输入法存在泄漏敏感数据的风险,敏感数据录入时建议禁用。
【代码示例】
禁用第三方输入法代码如下(敏感数据如密码不应使用第三方输入法):
- (BOOL)application:(UIApplication *)application shouldAllowExtensionPointIdentifier:(NSString *) extensionPointIdentifier
{
if ([extensionPointIdentifier isEqualToString:UIApplicationKeyboardExtensionPointIdentifier]) {
return NO;
}
return YES;
}
4.8.3.2 防止iOS7以上的系统进入后台自动截图
【规范要求】
iOS7以上系统中运行的APP应预防后台自动截图。
【详细说明】
当一个应用在后台被挂起时,系统会生成一个当前内容的屏幕快照,这样是为了让用户感觉到程序从后台唤起无缝恢复,但是该屏幕快照存在敏感数据泄露的风险。
【代码示例】
1)在进入后台后或切换其它到应用时隐藏当前Window;
- (void)applicationWillResignActive:(UIApplication *)application {
//当一个应用进入休眠时调用,如接到电话或切换应用,隐藏keyWindow
[UIApplication sharedApplication].keyWindow.hidden = YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application { //进入后台前隐藏keyWindow [UIApplication sharedApplication].keyWindow.hidden = YES; }
2)在进入后台后或切换其它到应用时给Window添加一张空白图片;
- (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:self.splash]; }
4.8.3.3.防止用户复制/粘贴敏感信息
【规范要求】
输入密码等敏感信息时,禁用复制、粘贴功能。
【详细说明】
禁用复制、粘贴可以防止敏感数据由剪切板中泄露。
【代码示例】
相关应用层提供的防止用户复制/粘贴的代码:
@interface JMRestrictedUITextField : UITextField
@end
@implementation JMRestrictedUITextField
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[[NSURL URLWithString:@""] setResourceValue:self forKey:@"" error:nil]; } return self; } - (BOOL)canPerformAction:(SEL)action withSender:(id)sender { if (action == @selector(cut:) || action == @selector(copy:)) return NO; else return YES; } @end
4.9.多余的功能
4.9.1 定义
“多余的功能”指开发人员将隐藏的后门程序功能或其他内部调试功能发布到生产环境中。例如:开发人员可能在一个混合应用程序中无意包含了一个作为注释的密码。另一个例子包括在测试阶段禁用了双因子身份验证。
4.9.2.风险
通过这些额外的功能代码,存在窃取敏感数据或访问未经授权功能的高风险。如果一个银行应用程序被植入了恶意代码,它不仅会窃取客户信息和资金,而且还损害了银行的声誉。这种恶意代码将启动一个传出连接,这将被视为真正的连接,而不是恶意的连接。尽管拥有各种安全控制,银行通过移动设备上的应用程序来检测恶意活动,是非常困难的。另一个例子是保险应用程序,如果开发人员将恶意代码片段注入任何保险应用程序中,那么窃取包含所有个人信息在内的客户数据是有很可能的。
4.9.3.防范方法
4.9.3.1.输出过滤
【规范要求】
发布时禁止输出调试日志信息,应用Release版本发布时应关闭Log输出。
【详细说明】
应用调试信息中可能隐藏关键的逻辑信息,会扩大应用的被攻击面。在发布时应该禁止输出调试日志信息。
4.10.其他
4.10.1.定义
十大移动风险之外的其它可能风险。
4.10.2 防范方法
4.10.2.1 密钥管理
【规范要求】
1)定期更换密钥;
2)登录密码等其它密码不能明文保存在移动终端本地;
3)支付密码不能保存在移动终端本地;
4)有自动检验弱口令的能力,当密码输入不符合复杂度要求时,不允许注册成功或修改密码,应提示客户不能使用简单密码。
5)比较新旧密码,不允许相同;
6)本地验证、限制密码长度不少于6位;
7)设置连续失败登录次数,超过限定次数应在短时间内锁定登录权限;
8)设置登录验证码防止暴力破解;