苹果之前建议使用ATS (App Transport Security)来保证传入安全,虽然会增加购买证书的成本,但是信息的安全传输还是比较重要的。有的通过允许所有的传输,比如允许所有的http 或者 https访问链接,如果是避免购买证书真是没有必要对于注重用户信息安全的公司来说。
信息的传输安全
1:升级app支持ATS ,所有的请求走https,购买一个符合规则的证书。这样一般通过抓包不是明文。
问题:但是如果用自建的证书,也就是中间人攻击,使app 和 服务器相信这个证书是有效证书可以解密,一些常用的抓包工具可以做到比如Charles则个抓包工具。
解决方法:验证证书的有效性。
1:验证证书的域名,就是你的证书的域名和你请求的域名一致。
2:校验证书链如下图验证整个证书链:
3:验证证书其他的信息比如,公钥,证书的有效性等所有字段都验证可以看这里https://www.jianshu.com/p/f279572f7890
typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {
AFSSLPinningModeNone,
//表示不做SSL pinning,只跟浏览器一样在系统的信任机构列表里验证服务端返回的证书。若证书是信任机构签发的就会通过,若是自己服务器生成的证书,这里是不会通过的。
AFSSLPinningModePublicKey,
//表示用证书绑定方式验证证书,需要客户端保存有服务端的证书拷贝,这里验证分两步,第一步验证证书的域名/有效期等信息,第二步是对比服务端返回的证书跟客户端返回的是否一致。
AFSSLPinningModeCertificate,
//这个模式同样是用证书绑定方式验证,客户端要有服务端的证书拷贝,只是验证时只验证证书里的公钥,不验证证书的有效期等信息。
};
对应的AFN 第三方请求库的代码是:
NSURL * url = [NSURL URLWithString:@"[https://www.google.com](https://www.google.com)"];
AFHTTPRequestOperationManager * requestOperationManager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:url];
dispatch_queue_t requestQueue = dispatch_create_serial_queue_for_name("kRequestCompletionQueue");
[requestOperationManager.completionQueue](http://requestOperationManager.completionQueue) = requestQueue;
AFSecurityPolicy * securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
//allowInvalidCertificates 是否允许无效证书(也就是自建的证书),默认为NO
//如果是需要验证自建证书,需要设置为YES
securityPolicy.allowInvalidCertificates = YES;
//validatesDomainName 是否需要验证域名,默认为YES;
//假如证书的域名与你请求的域名不一致,需把该项设置为NO;如设成NO的话,即服务器使用其他可信任机构颁发的证书,也可以建立连接,这个非常危险,建议打开。
//置为NO,主要用于这种情况:客户端请求的是子域名,而证书上的是另外一个域名。因为SSL证书上的域名是独立的,假如证书上注册的域名是[www.google.com](http://www.google.com),那么[mail.google.com](http://mail.google.com)是无法验证通过的;当然,有钱可以注册通配符的域名*.[google.com](http://google.com),但这个还是比较贵的。
//如置为NO,建议自己添加对应域名的校验逻辑。
securityPolicy.validatesDomainName = YES;
//validatesCertificateChain 是否验证整个证书链,默认为YES
//设置为YES,会将服务器返回的Trust Object上的证书链与本地导入的证书进行对比,这就意味着,假如你的证书链是这样的:
//GeoTrust Global CA
// Google Internet Authority G2
// *.[google.com](http://google.com)
//那么,除了导入*.[google.com](http://google.com)之外,还需要导入证书链上所有的CA证书(GeoTrust Global CA, Google Internet Authority G2);
//如是自建证书的时候,可以设置为YES,增强安全性;假如是信任的CA所签发的证书,则建议关闭该验证,因为整个证书链一一比对是完全没有必要(请查看源代码);
securityPolicy.validatesCertificateChain = NO;
requestOperationManager.securityPolicy = securityPolicy;
4:是否使用了代理,如果当前我们app 被访问的时候使用了代理,如果使用了代理那么不允许访问。如下代码:
+ (BOOL)getProxyStatus {
NSDictionary *proxySettings = NSMakeCollectable([(NSDictionary *)CFNetworkCopySystemProxySettings() autorelease]);
NSArray *proxies = NSMakeCollectable([(NSArray *)CFNetworkCopyProxiesForURL((CFURLRef)[NSURL URLWithString:@"[http://www.google.com](http://www.google.com)"], (CFDictionaryRef)proxySettings) autorelease]);
NSDictionary *settings = [proxies objectAtIndex:0];
NSLog(@"host=%@", [settings objectForKey:(NSString *)kCFProxyHostNameKey]);
NSLog(@"port=%@", [settings objectForKey:(NSString *)kCFProxyPortNumberKey]);
NSLog(@"type=%@", [settings objectForKey:(NSString *)kCFProxyTypeKey]);
if ([[settings objectForKey:(NSString *)kCFProxyTypeKey] isEqualToString:@"kCFProxyTypeNone"])
{
//没有设置代理
return NO;
}
else
{
//设置代理了
return YES;
}
}
使用token 的验证方式避免使用用户名密码验证
为了每次验证都用用户名密码的情况,web 用的是session + cookie 方式。App可以用类似token 的方式。用户第一次登录成功返回一个token,以后就用这个来做身份验证,退出登录删除这个token。为了防止token被截获,采用url签名的方式,把拼接token的url 采用某种规则来加密,这样以后就不用拼接token直接拼接sign签名好了。为了防止反复调用API,我们通过加上时间戳的方式处理,如果服务器收到客户端请求的时间和url上的时间戳差值在一个比如60秒则认为被截获,服务器拒绝请求。
对token或者用户敏感信息加密
比如采用DES 或者 AES 结合base64加密敏感的信息
防止App被反调试
在iOS上,您可以使用PT_DENY_ATTACH http://iosre.com/t/topic/8179
缓存技术
即使在keychain里面存储密码也要加密,然后设置访问的权限 SecAccessControlCreateFlags https://www.jianshu.com/p/72c1f9d3a58c
比如数据库里面的敏感数据加密存储,数据库文件加密。
键盘缓存
由于中文键盘开启的自动更正提示,用户输入的记录会被几记录下来。所以禁止一些控件自动更正禁掉,采用自定义键盘并且键盘点击不高亮。
其他的一些建议:
比如支付的时候支付宝微信这样的SDK建议签名什么的服务端来做,防止被拦截。
验证客户端的一些输入比如有些表情符号,如果MySQL 不升级支持接口会crash,这样我们可以过滤掉。还可以防止SQL注入攻击。
代码混淆。为了给逆向者读懂代码造成点麻烦。
越狱检测。给用户一些安全提示。
敏感逻辑的保护。还是给逆向者增加障碍,比如你的加密逻辑。
网友评论