常常作的網絡參數加密解密,以及防止數據重放以外,還提到了防範反編譯的風險,其實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..
下面就是混淆後的結果。
總結:
其實,原理應該就是在編譯過程當中,把須要混淆的代碼生成隨機字符串進行替換....