iOS加密实用总结

加密原则:

1   App代码安全,包括代码混淆,加密或者app加壳。
2   App数据存储安全,主要指在磁盘做数据持久化的时候所做的加密。
3   App网络传输安全,指对数据从客户端传输到Server中间过程的加密,防止网络世界当中其他节点对数据的窃听。

一:对称加密的话用AES最好,苹果系统(钥匙串也是用的AES加密),美国安全局,RSA中的对称加密用的都是AES加密。

  • 1 用户密码本地化的话,建议使用钥匙串加密。使用第三方SSkeychain.
    //SSkeychain第三方加密 采用AES()对本地化用户名 密码进行加密 对称加密
    NSString *userName = @"cerastes";
    NSString *password = @"新浪科技讯 北京时间5月25日早间消息,美国超级高铁公司Hyperloop Transportation Technologies(HTT)周二公布了一种智能材料。这种材料集成了传感器,将被用于制造超级高铁的车辆。HTT表示,这种材料主要由轻量级的碳纤维构成,强度超过任何钢材料10倍,而且比铝合金还轻,被称作“Vibranium”(汎合金,注:与漫画人物“美国队长”盾牌的材料同名)。利用这种材料可以降低车辆长途行驶所需的能耗。此外,材料内集成的传感器可以测量车辆的信息,并将其回传给运营中心。这些传感器可以实时读取车辆的温度、稳定度和完整度,确保安全和性能。Hyperloop超级高铁的时速最高可以达到700英里(约合1127公里),最先由特斯拉CEO伊隆·马斯克(Elon Musk)提出。目前,有两家公司试图将马斯克的设想变为现实,而HTT是其中之一。另一家名为Hyperloop One的公司本月早些时候在内华达州的沙漠中展示了测试轨道的初步工作。HTT尚未公布类似的磁力推进系统。该公司目前专注于安全性方面的创新。该公司计划利用两层智能材料去建造车辆,因此即使外层材料损毁,车辆仍可以安全运行。 HTT CEO德科·阿尔伯恩(Derk Ahlborn)表示:“安全性是我们系统最重要的一个方面。”(维金)";
    NSString *bundleID = [NSBundle mainBundle].bundleIdentifier;
    [SSKeychain setPassword:@"111" forService:bundleID account:@"ni"];
    [SSKeychain setPassword:password forService:bundleID account:@"wo"];
    [SSKeychain setPassword:@"333" forService:bundleID account:@"ta"];
    [SSKeychain deletePasswordForService:bundleID account:@"ni"];
    NSString *passwords = [SSKeychain passwordForService:bundleID account:@"wo"];
    NSLog(@"SSkeychain解密=====%@",passwords);
  • 2 一些简单又机密的数据可以AES加密
    Objective-c的AES加密和解密算法的具体实现代码如下:
 1.拓展NSData,增加AES256加密方法
//NSData+AES256.h
#import 
#import 
#import 
@interface NSData(AES256)
-(NSData *) aes256_encrypt:(NSString *)key;
-(NSData *) aes256_decrypt:(NSString *)key;
@end
 
//
//NSData+AES256.m
//
#import "NSData+AES256.h"
 
@implementation NSData(AES256)
 
- (NSData *)aes256_encrypt:(NSString *)key   //加密
{
    char keyPtr[kCCKeySizeAES256+1];
    bzero(keyPtr, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    NSUInteger dataLength = [self length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128,
                                          kCCOptionPKCS7Padding | kCCOptionECBMode,
                                          keyPtr, kCCBlockSizeAES128,
                                          NULL,
                                          [self bytes], dataLength,
                                          buffer, bufferSize,
                                          &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }
    free(buffer);
    return nil;
}
 
- (NSData *)aes256_decrypt:(NSString *)key   //解密
{
    char keyPtr[kCCKeySizeAES256+1];
    bzero(keyPtr, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    NSUInteger dataLength = [self length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    size_t numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128,
                                          kCCOptionPKCS7Padding | kCCOptionECBMode,
                                          keyPtr, kCCBlockSizeAES128,
                                          NULL,
                                          [self bytes], dataLength,
                                          buffer, bufferSize,
                                          &numBytesDecrypted);
    if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
 
    }
    free(buffer);
    return nil;
}
@end
2.拓展NSString,增加AES256加密方法,需要导入NSData+AES256.h
//
//NSString +AES256.h
//
 
#import 
#import 
#import 
 
#import "NSData+AES256.h"
 
@interface NSString(AES256)
 
-(NSString *) aes256_encrypt:(NSString *)key;
-(NSString *) aes256_decrypt:(NSString *)key;
 
@end
 
 
//
//NSString +AES256.h
//
 
@implementation NSString(AES256)
 
-(NSString *) aes256_encrypt:(NSString *)key
{
    const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding];
    NSData *data = [NSData dataWithBytes:cstr length:self.length];
    //对数据进行加密
    NSData *result = [data aes256_encrypt:key];
 
    //转换为2进制字符串
    if (result && result.length > 0) {
 
        Byte *datas = (Byte*)[result bytes];
        NSMutableString *output = [NSMutableString stringWithCapacity:result.length * 2];
        for(int i = 0; i < result.length; i++){
            [output appendFormat:@"%02x", datas[i]];
        }
        return output;
    }
    return nil;
}
 
-(NSString *) aes256_decrypt:(NSString *)key
{   
    //转换为2进制Data
    NSMutableData *data = [NSMutableData dataWithCapacity:self.length / 2];
    unsigned char whole_byte;
    char byte_chars[3] = {'\0','\0','\0'};
    int i;
    for (i=0; i < [self length] / 2; i++) {
        byte_chars[0] = [self characterAtIndex:i*2];
        byte_chars[1] = [self characterAtIndex:i*2+1];
        whole_byte = strtol(byte_chars, NULL, 16);
        [data appendBytes:&whole_byte length:1];
    }
 
    //对数据进行解密
    NSData* result = [data aes256_decrypt:key];
    if (result && result.length > 0) {
        return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding]autorelease];
    }
    return nil;
}
@end

二:mac加密:key值得来由。

网络登录注册传送密码建议使用hmac加密。

  • 官方模型分析:
    甲乙双方进行数据交换可以采取如下流程完成
    1、甲方向乙方公布摘要算法(就是指定要使用的摘要算法名)
    2、甲乙双方按照约定构造密钥,双方拥有相同的密钥(一般是一方构造密钥后通知另外一方,此过程不需要通过程序实现,就是双方约定个字符串,但是这个字符串可不是随便设定的,也是通过相关算法获取的)
    3、甲方使用密钥对消息做摘要处理,然后将消息和生成的摘要消息一同发送给乙方
    4、乙方收到消息后,使用甲方已经公布的摘要算法+约定好的密钥 对收到的消息进行摘要处理。然后比对自己的摘要消息和甲方发过来的摘要消息。甄别消息是否是甲方发送过来的。
  • iOS版,注册的时候传输一个MD5加密的密码(避免明文传输)过去,服务器返回一个随机数key,客服端key存本地。然后每次登录的时候用这个随机数key加密密码(加盐)。客服端存密码的MD5和key。这样客服端可以同样用key 加密密码。若账号异地登录(即手机里没有注册的key),则通过传输密码加盐(最好用当前时间加点其他文字,这样可以做权限保护,防止抓包获得key)获得key。

三:MD5加密

  • 加时间戳
  • 折叠追加字符串。
NSString *subString1 =[string substringToIndex:string.length -2];
    NSString *subString2 =[string substringFromIndex:string.length -2];
    NSString *newString = [NSString stringWithFormat:@"%@%@",subString2,subString1];
  • 多次MD5加密

四:RSA非对称加密。

  • 原理:http://blog.csdn.net/sean_cd/article/details/6966130
  • 购买了证书的话先传送公钥到客户端,再用AES传输数据。防止中间人攻击,证书startssl就是个不错的选择,有1年的免费服务。
  • 自制证书(苹果审核不一定通过),客服端存本地公钥,且每次使用时都要提示是否使用该不安全证书,有可能被中间人攻击。

五:token

  • 一般的登陆:
    客户端第一次发出登录请求时, 用户密码以明文的方式传输, 一旦被截获, 后果严重。因此密码需要加密,例如可采用RSA非对称加密。具体流程如下:
    客户端向服务器第一次发起登录请求(不传输用户名和密码)。
    服务器利用RSA算法产生一对公钥和私钥。并保留私钥, 将公钥发送给客户端。
    客户端收到公钥后, 加密用户密码, 向服务器发起第二次登录请求(传输用户名和加密后的密码)。
    服务器利用保留的私钥对密文进行解密,得到真正的密码。

  • token加密:
    再仔细核对上述登录流程, 我们发现服务器判断用户是否登录, 完全依赖于sessionId, 一旦其被截获, 黑客就能够模拟出用户的请求。于是我们需要引入token的概念: 用户登录成功后, 服务器不但为其分配了sessionId, 还分配了token, token是维持登录状态的关键秘密数据。在服务器向客户端发送的token数据,也需要加密。于是一次登录的细节再次扩展。
    客户端向服务器第一次发起登录请求(不传输用户名和密码)。服务器利用RSA算法产生一对公钥和私钥。并保留私钥, 将公钥发送给客户端。
    客户端收到公钥后, 加密用户密码,向服务器发送用户名和加密后的用户密码; 同时另外产生一对公钥和私钥,自己保留私钥, 向服务器发送公钥; 于是第二次登录请求传输了用户名和加密后的密码以及客户端生成的公钥。
    服务器利用保留的私钥对密文进行解密,得到真正的密码。 经过判断, 确定用户可以登录后,生成sessionId和token, 同时利用客户端发送的公钥,对token进行加密。最后将sessionId和加密后的token返还给客户端。
    客户端利用自己生成的私钥对token密文解密, 得到真正的token。图示如下:


    iOS加密实用总结_第1张图片

    login-300x181.png

登录保持(也就是http数据请求阶段)
引入token后,http请求被获取问题便可得到解决。 服务器将token和其它的一些变量, 利用散列加密算法得到签名后,连同sessionId一并发送给服务器; 服务器取出保存于服务器端的token,利用相同的法则生成校验签名, 如果客户端签名与服务器的校验签名一致, 就认为请求来自登录的客户端。(支付宝一样的机制)结构图如下:


iOS加密实用总结_第2张图片

keep_login.png

注:token失效的两种情况:

     用户登录出系统
     token在后台的规定时间内失效(每个token都是有时间效应的)

失效原理:在服务器端的redis中删除相应key为session的键值对。


token+散列算法

散列是信息的提炼,通常其长度要比信息小得多,且为一个固定长度。加密性强的散列一定是不可逆的,这就意味着通过散列结果,无法推出任何部分的原始信息。任何输入信息的变化,哪怕仅一位,都将导致散列结果的明显变化,这称之为雪崩效应。散列还应该是防冲突的,即找不出具有相同散列结果的两条信息。具有这些特性的散列结果就可以用于验证信息是否被修改。
散列算法可以用来加密token生成签名, 以便token信息不暴露在网络同时还能验证登录的有效性。

补充:

网络访问常用加密:

  • post请求那是必须的。抓包可以的到。
  • 加请求头,抓包可以得到。
  • 用key值做权限保护,key值的有效时间不宜过长。抓包可以的到。
  • 如果要做到相对安全的传送可以用时间戳MD5加密密码来过得key。
  • 要想非常安全的传输数据,建议使用https。抓包不可以,但是中间人攻击则有可能。防止中间人攻击:http://blog.csdn.net/u010731949/article/details/50538280

六:https加密:

  • 信任机构颁发的CA证书:如阿里云:https://www.aliyun.com/product/cas?spm=5176.7742214.416540.129.5amrlf

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
AFSecurityPolicy *securityPolicy = [[AFSecurityPolicy alloc] init];
[securityPolicy setAllowInvalidCertificates:NO];
[securityPolicy setSSLPinningMode:AFSSLPinningModeCertificate];
[securityPolicy setValidatesDomainName:YES];
[securityPolicy setValidatesCertificateChain:NO];
manager.securityPolicy = securityPolicy;

 
 * 自签名证书:没有那么安全。

# 七:参考文档(纯copy)

安全相关的基础概念

网络安全相关的概念非常之多,要在广度和深度上都有所造诣很困难。但如果只是站在保障App通信基本安全这个维度上,做到合理使用安全算法,比大部分人所预期的都要简单很多。以下这些基础概念是必备知识:

   •   对称加密算法,代表算法AES
   •   非对称加密算法,代表算法RSA,ECC
   •   电子签名,用于确认消息发送方的身份
   •   消息摘要生成算法,MD5,SHA,用于检测消息是否被第三方修改过

怎么样算安全?

安全问题说白了是信任问题,谈到信任一定要有一个可被信任的实体。假设某天A收到了一条“Message”,如果这个消息确实是来自B,消息就可以被信任,那么B就这安全问题当中可被信任的实体。

对于A来说只要满足三点就说明收到“Message”是安全的:

   •   Message有B的电子签名,表明消息确实是来自B。
   •   Message没有被篡改过。
   •   Message被某种加密算法加密过,只有A和B知道如何解密。

A和B的交谈如果放到网络世界当中,就是典型的Client-Server模式。和现实世界当中聊天不同的是,A和B所说的任何话都可以轻而易举的被其他人听到,隔墙随处有耳。

怎么去保证App网络传输的安全?

为了保证传输数据的安全,需要使用加密算法。在决定什么样的业务场景使用什么样的加密算法之前,先要了解我们的工具箱里有哪些可用工具。加密算法的工具箱里其实就两种工具:“对称”加密算法和“非对称”加密算法。清楚这两个分类是合理设计加密算法使用场景的大前提,两个分类里我们各挑选一个代表算法来研究,“对称”加密挑选AES,“非对称”加密选择RSA。了解AES和RSA之后我们再针对一些特定业务场景设计安全模型。

App网络安全实战

在App安全上的投入再多也不会过,不过安全问题上所投入的开发资源应该根据开发团队技术积累,产品发布deadline,用户规模及产品关注度等综合因素考量。结合这些因素我把App分为三类,各类App对安全级别的要求不同,投入产出也不同。

## 第一类,作坊式创业App

这些年伴随着移动互联网的创业潮,各式各样的app出现在用户的手机端。对于创业初期的团队来说,能把业务模型尽快实现上线当然是重中之重。但很多创业团队在安全上的投入几乎为零,所导致的安全问题比想象中的要严重。我见过不少使用http明文传输用户名密码的app,其中甚至包括一些知名传统企业。其实只要照顾到一些基础方面就能过滤掉大部分的安全漏洞了。这里提供一些小tip供创业初期团队参考:

Tip 1:尽量使用https

https可以过滤掉大部分的安全问题。https在证书申请,服务器配置,性能优化,客户端配置上都需要投入精力,所以缺乏安全意识的开发人员容易跳过https,或者拖到以后遇到问题再优化。https除了性能优化麻烦一些以外其他都比想象中的简单,如果没精力优化性能,至少在注册登录模块需要启用https,这部分业务对性能要求比较低。

Tip 2:不要传输密码

不知道现在还有多少app后台是明文存储密码的。无论客户端,server还是网络传输都要避免明文密码,要使用hash值。客户端不要做任何密码相关的存储,hash值也不行。存储token进行下一次的认证,而且token需要设置有效期,使用refresh token去申请新的token。

Tip 3:Post并不比Get安全

事实上,Post和Get一样不安全,都是明文。参数放在QueryString或者Body没任何安全上的差别。在Http的环境下,使用Post或者Get都需要做加密和签名处理。

Tip 4:不要使用301跳转

301跳转很容易被Http劫持攻击。移动端http使用301比桌面端更危险,用户看不到浏览器地址,无法察觉到被重定向到了其他地址。如果一定要使用,确保跳转发生在https的环境下,而且https做了证书绑定校验。

Tip 5:http请求都带上MAC

所有客户端发出的请求,无论是查询还是写操作,都带上MAC(Message Authentication Code)。MAC不但能保证请求没有被篡改(Integrity),还能保证请求确实来自你的合法客户端(Signing)。当然前提是你客户端的key没有被泄漏,如何保证客户端key的安全是另一个话题。MAC值的计算可以简单的处理为hash(request params+key)。带上MAC之后,服务器就可以过滤掉绝大部分的非法请求。MAC虽然带有签名的功能,和RSA证书的电子签名方式却不一样,原因是MAC签名和签名验证使用的是同一个key,而RSA是使用私钥签名,公钥验证,MAC的签名并不具备法律效应。

Tip 6:http请求使用临时密钥

高延迟的网络环境下,不经优化https的体验确实会明显不如http。在不具备https条件或对网络性能要求较高且缺乏https优化经验的场景下,http的流量也应该使用AES进行加密。AES的密钥可以由客户端来临时生成,不过这个临时的AES key需要使用服务器的公钥进行加密,确保只有自己的服务器才能解开这个请求的信息,当然服务器的response也需要使用同样的AES key进行加密。由于http的应用场景都是由客户端发起,服务器响应,所以这种由客户端单方生成密钥的方式可以一定程度上便捷的保证通信安全。

Tip 7:AES使用CBC模式

不要使用ECB模式,原因前面已经分析过,记得设置初始化向量,每个block加密之前要和上个block的秘文进行运算。

## 第二类,正规军App

All Traffic HTTPS

全站使用HTTPS,而且是强制使用。baidu到今天(2016.04.13)还没有强制使用HTTPS。所有的流量都应该在HTTPS上产生,没有人可以决定哪些流量是可以不用考虑安全问题的。如果自建长连接使用tcp,udp或者其他网络协议,也应该实现类似HTTPS的密钥协商流程。

Certificate Pinning

RSA的签名机制虽然看着安全,一旦出现上游证书颁发机构私钥泄漏,或者签名流程发现漏洞等情况,中间人攻击还是会导致数据被第三方破解甚至被钓鱼。Certificate Pinning是一种与服务器证书强绑定的机制,要么绑定证书本身,需要证书更新机制配合加强安全性,要么使用私钥绑定,这样更新证书的时候只要保证私钥不变即可。现在流行的HTTP framework,iOS端如AFNetworking,Android端如OKHttp都支持Certificate Pinning。

Perfect Forward Secrecy

很多人会觉得非对称加密算法足够安全,只要使用了RSA或者AES,加密过后的数据就认为安全。但没有绝对的安全,无论是RSA或者AES算法本身都有可能在未来某一天被破解,正如当年的DES,甚至有传言NSA正如当年掌握了differential cryptanalysis一样,现在已经获取了某种方法来破解当前互联网当中的部分网络流量,至于到底是RSA还是AES就不得而知了。

未来计算机的计算能力是个未知数,或许某一天brute force能够暴力破解的密钥长度会远超128bits(现阶段上限应该在80bits)。

2014年1月3日,美国国家安全局(NSA)正在研发一款用于破解加密技术的量子计算机,希望破解几乎所有类型的加密技术。

即使算法本身没有被破解,密钥也有可能被泄漏,技术上的原因或者政策上的因素都可能导致RSA或者ECC的私钥被泄漏。所以尽可能针对不同的session使用不同的key能够使的我们的数据更佳安全。

Forward Secrecy就是为了避免某个私钥的泄漏或者被破解而导致历史数据一起泄漏。现在google的https配置所使用的是TLS_ECDHE_RSA算法,每次对称密钥的协商都是使用ECC生成临时的公钥私钥对(之前提到过ECC在快速生成密钥对上有优势),身份验证使用RSA算法进行签名。

每天跟踪信息安全动态

安全的攻防战不会有穷尽的一天,算法的更替会伴随着人类对知识的无尽渴望延绵至不可预知的未来。AES说不定哪天被破解了,openSSL可能又出现新的漏洞了,google又提倡新的安全模型了,NSA的量子计算机说不准已经在悄悄解密google的流量了,每天跟踪八卦最新业界动态才是码农避免因bug而背黑锅的不二法宝。

## 第三类,带节操正规军App

现在互联网早已渗入每个人的平常生活当中,当我们的行为越来越多的迁移到互联网这个媒介当中之后,行为本身及所产生的关联数据都将被滴水不漏的记录起来,特别是在大数据研究兴起的当下,服务提供商总是希望尽可能多的记录用户所有的行为数据。每个互联网产品的使用者都成了样本,你的购物记录,商品浏览历史,搜索引擎搜索记录,打车记录,租房记录,股票记录,甚至聊天记录等等都是样本,毫不夸张的说,如果将淘宝,微信,支付宝,快滴,美团等等高频次产品数据统一分析,基本上可以将你的身高,性别,年龄,三维,家庭住址,恋爱史,家庭成员,甚至是个人喜好,性格等等完美的呈现出来,其后果远不是一个骚扰电话带来的隐私泄漏那么简单。

移动互联网的大部分使用者还不具备强烈的安全意识,当你用手机号作为登录id方便记忆的同时,骚扰电话就可能随时来临,你在百度输入租房关键字,下一秒中介就已经电话打上门。当你允许app上传通讯录匹配可能认识的好友同时,你认识哪些人就变得一清二楚,你p2p借贷未及时归还时,你的亲朋好友第二天就收到了催债电话。我们在享受移动互联网的便利同时,付出的是个人隐私这种隐形成本。下一次,当我们感叹新app好用便利的同时,静思三分钟,好好想想我们的哪些隐私又被当白菜卖了。

在互联网受众的安全意识普遍觉醒之前,只能靠app开发商,服务提供商的节操来保证用户信息隐私安全。

带节操的App在打算记录用户行为或者数据之前会考虑下是不是真的有需要,用户的确会有需要查询历史购买记录,但有多少人会在意自己几年前花几个小时浏览了杜蕾斯的产品。

服务器作为数据存储或者转发的媒介是不是真的需要了解真实的数据为何?现在WhatsApp,Telegram都已经支持端到端的加密聊天方式,服务器本身看到的都是秘文,只做秘文转发处理,带着这样的节操设计产品,用户才会觉得安全。

WhatsApp的端到端加密安全模型是怎么样实现的呢?非常值得学习。

简单来说是严格遵循forward secrecy。每个用户在注册成功之后会在服务器存一对永久的Identity Key,一对临时的Signed Pre Key(Signed Pre Key由Identity Key签名,每隔一段时间变化一次),n对临时的One-Time Pre Key(每次建立session消耗一个)。

每次session开始建立的时候使用Identity Key,Signed Pre Key, One Time Key生成Master Secret。Master Secret再通过HKDF算法生成对称加密使用的Root Key,Chain Key,Message Key。

Forward Secrecy体现在每次sender发送的消息被ack后,都会交换新的临时ECC Key对,并更新Root Key,Chain Key,Message Key。这样网络中的流量即使被第三方缓存起来,而且某一天某个Key Pair的私钥被破解,也不会对之前的流量产生安全影响。ECC Key对会随着消息的发送不停的“Ratcheting”。这是属于非对称加密的Forward Secrecy。

在sender的消息被ack之前,也就是新的ECC Key对交换成功之前,Message Key也会通过HKDF算法不停的“Ratcheting”,确保每条消息所使用的对称密钥也不相同。这是属于对称加密的Forward Secrecy。

有兴趣深入了解的同学可以自己google:WhatsApp Security WhitePaper。

你可能感兴趣的:(iOS加密实用总结)