常常作的网络参数加密解密,以及防止数据重放以外,还提到了防范反编译的风险,其实Apple算比较安全的了,反编译过来也就看到.h文件....但把代码混淆仍是会比较好些。html
简答说,HTTPS 就是 HTTP协议加了一层SSL协议的加密处理,SSL 证书就是遵照 SSL协议,由受信任的数字证书颁发机构CA(如GlobalSign,wosign),在验证服务器身份后颁发,这是须要花钱滴,签发后的证书做为公钥通常放在服务器的根目录下,便于客户端请求返回给客户端,私钥在服务器的内部中心保存,用于解密公钥。java
一、客户端发送请求,服务器返回公钥给客户端;
二、客户端生成对称加密秘钥,用公钥对其进行加密后,返回给服务器;
三、服务器收到后,利用私钥解开获得对称加密秘钥,保存;
四、以后的交互都使用对称加密后的数据进行交互。ios
谈下证书
简单说,证书有两种,一种是正经的:算法
一种是不正经的:sql
若是遇到正经的证书,咱们直接用AFNetworking 直接请求就行了,AFNetworking 内部帮咱们封装了HTTPS的请求方式,可是大部分公司接口都是不正经的证书,这时须要咱们作如下几步:
一、将服务器的公钥证书拖到Xcode中
二、修改验证模式数据库
manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey];
原理:
简单来讲,就是你本能够修改AFN这个设置来容许客户端接收服务器的任何证书,可是这么作有个问题,就是你没法验证证书是不是你的服务器后端的证书,给中间人攻击,即经过重定向路由来分析伪造你的服务器端打开了大门。vim
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy defaultPolicy];
securityPolicy.allowInvalidCertificates = YES;
openssl x509 -in <你的服务器证书>.pem -outform der -out server.cer
而后将生成的server.cer文件,若是有自建ca,再加上ca的cer格式证书,引入到app的bundle里,AFNetworking在后端
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy AFSSLPinningModeCertificate];
或者数组
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy AFSSLPinningModePublicKey];
状况下,会自动扫描bundle中.cer的文件,并引入,这样就能够经过自签证书来验证服务器惟一性了。浏览器
AFSecurityPolicy分三种验证模式:
这个模式表示不作SSL pinning,
只跟浏览器同样在系统的信任机构列表里验证服务端返回的证书。若证书是信任机构签发的就会经过,如果本身服务器生成的证书就不会经过。
这个模式表示用证书绑定方式验证证书,须要客户端保存有服务端的证书拷贝,这里验证分两步,第一步验证证书的域名有效期等信息,第二步是对比服务端返回的证书跟客户端返回的是否一致。
这个模式一样是用证书绑定方式验证,客户端要有服务端的证书拷贝,
只是验证时只验证证书里的公钥,不验证证书的有效期等信息。只要公钥是正确的,就能保证通讯不会被窃听,由于中间人没有私钥,没法解开经过公钥加密的数据。
用 POST 请求提交用户的隐私数据,仍是不能彻底解决安全问题。所以:咱们常常会用到加密技术,好比说在登陆的时候,咱们会先把密码用MD5加密再传输给服务器 或者 直接对全部的参数进行加密再POST到服务器。
最基础的是咱们发送网络请求时,使用get
和post
方式发送请求。二者具体区别就不作解释了,只是引出相关安全性问题
get
:将参数暴露在外,(绝对不安全-->明文请求或者傻瓜式请求)。post
:将参数放到请求体body中,(相对于get比较安全-->可是咱们能够很容易用一些软件截获请求数据。好比说Charles(青花瓷)
)Charles
(大部分app的数据来源都使用该工具来抓包,并作网络测试)
数据安全的原则
不容许
传输用户隐私数据的明文
,(即:App网络传输安全,指对数据从客户端传输到Server中间过程的加密,防止网络世界当中其余节点对数据的窃听)。不容许
保存用户隐私数据的明文
,(即:App数据存储安全,主要指在磁盘作数据持久化的时候所作的加密)。代码安全
,(即:包括代码混淆,加密或者app加壳)。要想很是安全的传输数据,建议使用https。抓包不能够,可是中间人攻击则有可能。建议双向验证防止中间人攻击,能够参考下文篇章。
二、经常使用加密算法
编码方案 Base64
哈希(散列)函数 MD5(消息摘要算法)
SHA1
SHA256
对称加密算法 DES
AES
非对称加密算法 RSA
HTTPS HTTP+SSL协议
三、经常使用加密方式
1.经过简单 BASE64编码 防止数据明文传输
2.对普通请求、返回数据,生成MD5校验(MD5中加入动态密钥),进行数据完整性(简单防篡改,安全性较低,优势:快速)校验
3.对于重要数据,使用RSA进行数字签名,起到防篡改做
4.对于比较敏感的数据,如用户信息(登录、注册等),客户端发送使用RSA加密,服务器返回使用DES(AES)加密
5.要想很是安全的传输数据,建议使用https。抓包不能够,可是中间人攻击则有可能。建议双向验证防止中间人攻击
Base64简单说明
描述:Base64能够成为密码学的基石,很是重要。
特色:能够将任意的二进制数据进行Base64编码
结果:全部的数据都能被编码为并只用65个字符(A~Z a~z 0~9 + / =)就能表示的文本文件。
注意:对文件进行base64编码后文件数据的变化:编码后的数据~=编码前数据的4/3,会大1/3左右。
Base64编码原理和处理过程
// 对一个字符串进行base64编码,而且返回
-(NSString *)base64EncodeString:(NSString *)string {
// 1.先转换为二进制数据
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; // 2.对二进制数据进行base64编码,完成以后返回字符串 return [data base64EncodedStringWithOptions:0]; } // 对base64编码以后的字符串解码,而且返回 -(NSString *)base64DecodeString:(NSString *)string { // 注意:该字符串是base64编码后的字符串 // 1.转换为二进制数据(完成了解码的过程) NSData *data = [[NSData alloc]initWithBase64EncodedString:string options:0]; // 2.把二进制数据在转换为字符串 return [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; } //---------------------------<#我是分割线#>------------------------------// NSLog(@"%@",[self base64EncodeString:@"A"]); NSLog(@"%@",[self base64DecodeString:@"QQ=="]);
PS.终端执行编码和解码
如:
编码:base64 123.png -o 123.txt 解码:base64 123.txt -o test.png -D
哈希(散列)函数
特色:
用途:
MD五、SHA一、SHA512
简单介绍:
特色:
应用:
注意点:
PS.暴力破解是指经过将明文和生成的密文进行配对,生成强大的数据库,在数据库中搜索,在这里就能够破解密码。破解网址 http://www.cmd5.com
提高MD5加密安全性,解决办法
#define salt @"1342*&%&shlfhs390(*^^6R%@@KFGKF"
2.先加密+乱序
3.乱序|加盐,屡次MD5加密等
消息认证机制(HMAC)简单说明
简单示例
#pragma mark - md5加密方法
- (NSString *)md5String {
const char *str = self.UTF8String; uint8_t buffer[CC_MD5_DIGEST_LENGTH]; CC_MD5(str, (CC_LONG)strlen(str), buffer); return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH]; } #pragma mark - HMACMD5加密方法 - (NSString *)hmacMD5StringWithKey:(NSString *)key { const char *keyData = key.UTF8String; const char *strData = self.UTF8String; uint8_t buffer[CC_MD5_DIGEST_LENGTH]; CCHmac(kCCHmacAlgMD5, keyData, strlen(keyData), strData, strlen(strData), buffer); return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH]; } /** * 返回二进制 Bytes 流的字符串表示形式 * @param bytes 二进制 Bytes 数组 * @param length 数组长度 * @return 字符串表示形式 */ - (NSString *)stringFromBytes:(uint8_t *)bytes length:(int)length { NSMutableString *strM = [NSMutableString string]; for (int i = 0; i < length; i++) { [strM appendFormat:@"%02x", bytes[i]]; } return [strM copy]; } //---------------------------<#我是分割线#>------------------------------// // md5加密调用 NSLog(@"%@",[@"520it" md5String]); // (明文+加盐)MD5加密调用 NSLog(@"%@",[[@"520it" stringByAppendingString:salt] md5String]); // hmacMD5加密调用(先加密+乱序) NSLog(@"%@",[@"520it" hmacMD5StringWithKey:@"xiaomage"]);
简单示例
/**
* 加密字符串并返回base64编码字符串
*
* @param string 要加密的字符串
* @param keyString 加密密钥
* @param iv 初始化向量(8个字节)
*
* @return 返回加密后的base64编码字符串
*/
- (NSString *)encryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv;
/**
* 解密字符串
*
* @param string 加密并base64编码后的字符串
* @param keyString 解密密钥
* @param iv 初始化向量(8个字节)
*
* @return 返回解密后的字符串
*/
- (NSString *)decryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv; // 调用 EncryptionTools *encrypt = [EncryptionTools sharedEncryptionTools]; NSLog(@"%@",[encrypt encryptString:@"LN123" keyString:@"LN" iv:nil]); NSLog(@"%@",[encrypt decryptString:@"OPcTMDB5paivqtYo9Fj+hQ==" keyString:@"LN" iv:nil]);
简单示例
// 公钥加密时调用类方法:
+ (NSString *)encryptString:(NSString *)str publicKey:(NSString *)pubKey;
+ (NSData *)encryptData:(NSData *)data publicKey:(NSString *)pubKey; // 私钥解密时调用类方法 + (NSString *)decryptString:(NSString *)str privateKey:(NSString *)privKey; + (NSData *)decryptData:(NSData *)data privateKey:(NSString *)privacy; /** 调用 */ NSString *str = [RSAUtil encryptString: @"LN" publicKey:RSA_Public_key]; NSLog(@"RSA公钥加密数据-->\n%@",str); NSString *str1 = [RSAUtil decryptString:str privateKey:RSA_Privite_key]; NSLog(@"RSA私钥解密数据-->%@",str1);
MAC上生成公钥、私钥的方法,及使用
# MAC上生成公钥、私钥的方法
@code
1.打开终端,切换到本身想输出的文件夹下 2.输入指令:openssl(openssl是生成各类秘钥的工具,mac已经嵌入) 3.输入指令:genrsa -out rsa_private_key.pem 1024 (生成私钥,java端使用的) 4.输入指令:rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout (生成公钥) 5.输入指令:pkcs8 -topk8 -in rsa_private_key.pem -out pkcs8_rsa_private_key.pem -nocrypt(私钥转格式,在ios端使用私钥解密时用这个私钥) 注意:在MAC上生成三个.pem格式的文件,一个公钥,两个私钥,均可以在终端经过指令vim xxx.pem 打开,里面是字符串,第三步生成的私钥是java端用来解密数据的,第五步转换格式的私钥iOS端能够用来调试公钥、私钥解密(由于私钥不留在客户端) iOS端公钥加密私钥解密、java端公钥加密私钥解密,java端私钥加密公钥解密都容易作到,iOS不能私钥加密公钥解密,只能用于验签 @endcode
https简单说明
全称:Hyper Text Transfer Protocol over Secure Socket Layer
),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。SSL层
,HTTPS的安全基础是SSL,所以加密的详细内容就须要SSL。 它是一个URI scheme(抽象标识符体系),句法类同http:体系。用于安全的HTTP数据传输。注意
HTTPS和HTTP区别
ca申请证书
,通常免费证书不多,须要交费。ssl加密传输协议
。前者是80
,后者是443
。SSL+HTTP协议
构建的可进行加密传输、身份认证的网络协议,比http协议安全。实现代码
方案一:若是是本身使用NSURLSession来封装网络请求
// 1.建立session
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
// 2.建立Task
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://kyfw.12306.cn/otn"]] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { // 3.解析数据 NSLog(@"%@---%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding],error); }]; // 4.执行task [dataTask resume]; #pragma mark - 遵照<NSURLSessionDataDelegate> // 若是发送的请求是https的,那么才会调用该方法 -(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler { /** 判断服务器传给咱们的信任的类型,只有是【服务器信任的时候,才安装证书】 NSURLSessionAuthChallengeDisposition 如何处理证书 NSURLAuthenticationMethodServerTrust 服务器信任 */ if(![challenge.protectionSpace.authenticationMethod isEqualToString:@"NSURLAuthenticationMethodServerTrust"]) { return; } NSLog(@"%@",challenge.protectionSpace); /* NSURLCredential 受权信息 NSURLSessionAuthChallengeUseCredential = 0, 使用该证书 安装该证书 NSURLSessionAuthChallengePerformDefaultHandling = 1, 默认采用的方式,该证书被忽略 NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2, 取消请求,证书忽略 NSURLSessionAuthChallengeRejectProtectionSpace = 3, 拒绝 */ NSURLCredential *credential = [[NSURLCredential alloc]initWithTrust:challenge.protectionSpace.serverTrust]; completionHandler(NSURLSessionAuthChallengeUseCredential,credential); // 注意:并非全部的https的请求都须要安装证书(受权)的,请求一些大型的网站有的是强制安装的,如:苹果官网https://www.apple.com }
方案二:若是使用AFN网络请求
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// 更改解析方式(请求网页源码应使用原始解析)
manager.responseSerializer = [AFHTTPResponseSerializer serializer]; // 设置对证书的处理方式 // 容许自签名证书,必须的 manager.securityPolicy.allowInvalidCertificates = YES; // 是否验证域名的CN字段(不是必须的,可是若是写YES,则必须导入证书) manager.securityPolicy.validatesDomainName = NO; [manager GET:@"https://kyfw.12306.cn/otn" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@"success---%@",[[NSString alloc]initWithData:responseObject encoding:NSUTF8StringEncoding]); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"error---%@",error); }];
API重放攻击(Replay Attacks)又称重播攻击、回放攻击,这种攻击会不断恶意或欺诈性地重复一个有效的API请求。攻击者利用网络监听或者其余方式盗取API请求,进行必定的处理后,再把它从新发给认证服务器,是黑客经常使用的攻击方式之一。
否,加密能够有效防止明文数据被监听,可是却防止不了重放攻击。
通常使用以时间戳做为传参,后台协商响应时间差范围,参考三次握手协议两边商量序列号,当发过来的序列号为服务器也存在的序列号则丢弃。
使用签名以后,能够对请求的身份进行验证。但不一样阻止重放攻击,即攻击者截获请求后,不对请求进行任何调整。直接使用截获的内容从新高频率发送请求。
API网关提供了一套有效防止重放攻击的方法。开启API网关的重放,须要您使用“阿里云APP”的认证方式。经过这种签名认证方式,每一个请求只能被使用一次,从而防止重放。
阿里云APP:是基于请求内容计算的数字签名,用于API网关识别用户身份。客户端调用API时,须要在请求中添加计算的签名。API网关在收到请求后会使用一样的方法计算签名,同用户计算的签名进行比较,相同则验证经过,不一样则认证失败。这种认证的签名方式请参照:请求签名
在API网关的签名中,提供X-Ca-Timestamp、X-Ca-Nonce两个可选HEADER,客户端调用API时一块儿使用这两个参数,能够达到防止重放攻击的目的。
不修改内容
X-Ca-Timestamp:发起请求的时间,能够取自机器的本地实现。当API网关收到请求时,会校验这个参数的有效性,偏差不超过15分钟。
X-Ca-Nonce:这个是请求的惟一标识,通常使用UUID来标识。API网关收到这个参数后会校验这个参数的有效性,一样的值,15份内只能被使用一次。
1、在项目根目录下新建confuse.sh 和 gbFunc.list 文件
说明:
confuse.sh 文件在编译过程当中会执行gbFunc.list 用于自动混淆代码时,存放过滤出来须要混淆的方法名
touch confuse.sh
touch gbFunc.list
2、新建GBConfuse.h
说明:
GBConfuse.h 是在自动混淆代码时,将会把自动生成的字符串定义成宏,存放在此文件,也便于查看。
注意:须要把.h文件移到项目文件外,由于放项目文件中,到时被反编译过来,仍是能获得GBConfuse.h里面的东西的,就能经过比对,获得方法。(后面用class-dump反编译过来就明白了...)
在confuse.sh中添加以下代码
#!/usr/bin/env bash
TABLENAME=symbols SYMBOL_DB_FILE="symbols" #func.list路径 STRING_SYMBOL_FILE="$PROJECT_DIR/GBFunc.list" #项目文件路径 CONFUSE_FILE="$PROJECT_DIR/Safedemo" #Confuse.h路径 HEAD_FILE="$PROJECT_DIR/GBConfuse.h" export LC_CTYPE=C #取以.m或.h结尾的文件以+号或-号开头的行 |去掉全部+号或-号|用空格代替符号|n个空格跟着<号 替换成 <号|开头不能是IBAction|用空格split字串取第二部分|排序|去重复|删除空行|删掉以init开头的行>写进func.list grep -h -r -I "^[-+]" $CONFUSE_FILE --include '*.[mh]' |sed "s/[+-]//g"|sed "s/[();,: *^/{]/ /g"|sed "s/[ ]*</</"| sed "/^[ ]*IBAction/d"|awk '{split($0,b," "); print b[2]; }'| sort|uniq |sed "/^$/d"|sed -n "/^GBSAFE_/p" >$STRING_SYMBOL_FILE #维护数据库方便往后做排重,如下代码来自念茜的微博 createTable() { echo "create table $TABLENAME(src text, des text);" | sqlite3 $SYMBOL_DB_FILE } insertValue() { echo "insert into $TABLENAME values('$1' ,'$2');" | sqlite3 $SYMBOL_DB_FILE } query() { echo "select * from $TABLENAME where src='$1';" | sqlite3 $SYMBOL_DB_FILE } ramdomString() { openssl rand -base64 64 | tr -cd 'a-zA-Z' |head -c 16 } rm -f $SYMBOL_DB_FILE rm -f $HEAD_FILE createTable touch $HEAD_FILE #这里也要作修改 echo '#ifndef GBConfuse_h #define CodeConfuse' >> $HEAD_FILE echo "//confuse string at `date`" >> $HEAD_FILE cat "$STRING_SYMBOL_FILE" | while read -ra line; do if [[ ! -z "$line" ]]; then ramdom=`ramdomString` echo $line $ramdom insertValue $line $ramdom echo "#define $line $ramdom" >> $HEAD_FILE fi done echo "#endif" >> $HEAD_FILE sqlite3 $SYMBOL_DB_FILE .dump
须要修改的代码在于文件路径:
添加 Run Script
添加 PCH 文件
在ViewController中添加以"GBSAFE_"为前缀的测试方法
测试
运行报错以下:
缘由是.sh文件没有权限,因此须要去开启权限。
在confuse.sh文件目录下,执行命令:
chmod 755 confuse.sh
运行成功!
先打包一个.ipa安装包进行测试!
先不进行代码混淆:
把.ipa文件类型改为.zip,解压获得.app文件
新建Hear文件夹用于保存反编译后获得的文件:
用class-dump进行反编译
class-dump -H 要破解的可执行文件路径 -o 破解后的头文件存放路径
获得没有进行代码混淆的文件:
能够看到都是项目中一些.h文件,打开能够看到完整的方法名....
而后客户说测试公司说不安全...
须要进行代码混淆...
在PCH文件中,引用GBConfuse.h:
从新打包..就能够获得混淆后的.ipa..
下面就是混淆后的结果。
总结:
其实,原理应该就是在编译过程当中,把须要混淆的代码生成随机字符串进行替换....