伴隨著移動產(chǎn)品廣泛應(yīng)用與快速發(fā)展次慢,移動客戶端的安全問題越來越受重視。我這里主要談?wù)刬OS移動端的安全架構(gòu)設(shè)計今布。
一经备、前言
移動端的安全一般可以理解為兩個方面:本地安全、通信安全部默。
1侵蒙、本地安全:
本地安全主要指客戶端本地環(huán)境與數(shù)據(jù)的安全,以及代碼被破解獲得所導(dǎo)致的安全問題傅蹂,如:明文存儲問題纷闺,惡意二次打包問題,越權(quán)操作問題等份蝴。2犁功、通信安全:
通信安全主要指客戶端與服務(wù)端進(jìn)行數(shù)據(jù)交互時被攔截破獲導(dǎo)致的安全問題。如采取明文進(jìn)行密碼或者數(shù)據(jù)傳輸?shù)葐栴}婚夫。
關(guān)于一些移動端安全的認(rèn)識還有web安全等等浸卦,請參考文章:移動端本地安全解決方案
二、安全加密基礎(chǔ)的快速認(rèn)識
加密分為對稱加密和非對稱加密案糙。
1限嫌、對稱加密
加密使用的密鑰和解密使用的密鑰是相同的靴庆。也就是說,加密和解密都是使用的同一個密鑰怒医,也就是共享密鑰密碼炉抒。(ps:這個很好理解吧) 常用的對稱加密算法:
名稱 | 英文 |
---|---|
DES | Data Encryption Standard |
3DES | Triple DES |
AES | dvanced Encryption Standard |
2、非對稱加密
加密使用的密鑰和解密使用的密鑰是不相同的稚叹。 (ps:這個不好理解焰薄?不好理解請好好看看非對稱加密算法原理) 簡單來說就是有一套算法可以實(shí)現(xiàn)你用公鑰加密的信息,對方用保留的私鑰進(jìn)行解密扒袖。
常說的公鑰密碼就是指非對稱密碼塞茅,公鑰加密就是一種非對稱加密。
最常用的是RSA算法僚稿。RSA的演算方法是:
1)用戶選擇2個夠大的保密質(zhì)數(shù)q凡桥、p(一般為100位以上十進(jìn)數(shù)) 2)令n=pq,n是公開的蚀同,從n分解除qp是極其困難的缅刽。 n的歐拉函數(shù):Φ(n)=(p-1)(q-1) Φ(n)小于等于n,并與n互質(zhì) 3)選擇一個相對大的整數(shù)e作為加密指數(shù)蠢络,使e與Φ(n)互質(zhì)衰猛, 4)解同等方程: ed=1modΦ(n) 求出解密指數(shù)d 5)設(shè)M、C分別為要加密的明文和被加密的密文(M刹孔、C小于n) 則:加密運(yùn)算為:C=Memod n 解密運(yùn)算為:M=Cdmod n 6)每個用戶都有一組密鑰(e啡省、d、n) (e髓霞,n)為PK'可以公開在手冊上的公鑰卦睹,e為加密指數(shù), (d方库,n)為SK’(或PV)是用戶保密的私鑰 將p.q銷毀 7)要求明文X 舉例: 1) 選兩個質(zhì)數(shù): p=47 q=71 2)計算: n=pq=3337 Φ(n)=(47-1)(71-1)=3220 3) e必須與Φ(n)互質(zhì)结序,選e=79 4) 計算:ed=1modΦ(n)=1mod(3220) d=1019 將e、n公布纵潦,d保密徐鹤,p.q消毀 如有一明文 M=6882326879666683要加密,則先將M分割成多塊: m1=688,m2=232,m3=687,m4=966,m5=668,m6=3 將第1塊M1加密后得密文C1: C1=m1e(mod3337)=68879(mod3337)=1570 依次對各區(qū)塊加密后得密文C: C=15702756271422762423158 對C1解密得m1 M1=C1d(mod3337)=15701019(mod3337)=688 依次解密得原文M邀层。
那么問題來了返敬,我們遇到的PBE(Password Based Encryption,基于口令加密)加密啊都是什么呢寥院。詳情可以去了解下劲赠,這里強(qiáng)調(diào)一點(diǎn),PBE算法的應(yīng)用還是在對稱加密范疇。至于哪種加密方案適合自己的場景凛澎,這也是我們今天iOS移動端安全架構(gòu)設(shè)計的時候需要考慮的泌绣。
知識點(diǎn)延伸:
1、對稱密碼與公鑰密碼對比预厌,消息認(rèn)證碼與數(shù)字簽名的對比
對象屬性 | 對稱密碼 | 公鑰密碼(非對稱密碼) |
---|---|---|
發(fā)送者 | 用共享密鑰加密-雙方持有 | 用公鑰加密 |
接收者 | 用共享密鑰加密-雙方持有 | 用私鑰解密 |
密鑰配送問題 | 存在 | 不存在,但公鑰需要另外認(rèn)證 |
機(jī)密性 | ? | ? |
對象屬性 | 消息認(rèn)證碼 | 數(shù)字簽名 |
---|---|---|
發(fā)送者 | 用共享密鑰計算MAC值 | 用私鑰生成簽名 |
接收者 | 用共享密鑰計算MAC值 | 用公鑰驗(yàn)證簽名 |
密鑰配送問題 | 存在 | 不存在元媚,但公鑰需要另外認(rèn)證 |
完整性 | ? | ? |
認(rèn)證 | ?(僅限通信對象雙方) | ? (可適用于任何第三方) |
防止否認(rèn) | ? | ? |
2轧叽、公鑰密碼與數(shù)字簽名的密鑰適用方式
對象屬性 | 公鑰 | 私鑰 |
---|---|---|
公鑰密碼 | 發(fā)送者加密時使用 | 接收者解密時使用 |
數(shù)字簽名 | 驗(yàn)證者驗(yàn)證簽名時使用 | 簽名者生成簽名時使用 |
誰持有密鑰? | 只要需要刊棕,可任何人都可以持有 | 個人持有 |
數(shù)字簽名就是利用非對稱加密的原理炭晒,只是用法下不一樣,反著的甥角。另外為公鑰加上數(shù)字簽名就是證書网严。
二、iOS移動端設(shè)計的安全考量
移動客戶端設(shè)計時嗤无,除了上述寬泛的本地安全和通信安全需要考量震束,具體到模塊與業(yè)務(wù)需要開發(fā)者作哪些思考呢?本地密碼存儲安全怎么保證当犯,客戶端web頁面怎么防止被劫持垢村,客戶端在設(shè)計交易時如何考慮安全性等等問題。如今蘋果開始強(qiáng)制接口使用HTTPS協(xié)議也是為為了增強(qiáng)安全性嚎卫,但開發(fā)者在客戶端設(shè)計之初也需要考慮這些安全問題嘉栓,建立一些基礎(chǔ)的安全模塊。
(ps:至于涉及到金融類App考慮的安全問題就更多拓诸,如交易安全侵佃,私鑰如何存儲等)
1、安全需求分析
加密原則:
- App代碼安全奠支,包括代碼混淆馋辈,加密或者app加殼。
- App數(shù)據(jù)存儲安全胚宦,主要指在磁盤做數(shù)據(jù)持久化的時候所做的加密首有。
- App網(wǎng)絡(luò)傳輸安全,指對數(shù)據(jù)從客戶端傳輸?shù)絊erver中間過程的加密枢劝,防 止網(wǎng)絡(luò)世界當(dāng)中其他節(jié)點(diǎn)對數(shù)據(jù)的竊聽井联。
本地存儲安全:
1)、明文存儲您旁,過度依賴系統(tǒng)安全性(iOS:Keychain/UserDefault)
2)烙常、惡意二次打包
3)、容易被逆向,被調(diào)試
4)蚕脏、敏感信息寫入代碼
網(wǎng)絡(luò)通信安全:
1)侦副、HTTP傳輸被劫持(蘋果開始強(qiáng)制接口使用HTTPS協(xié)議)
2)、明文傳輸數(shù)據(jù)
另外由本地安全延伸出來:
1)驼鞭、本地自動登錄如何存儲私鑰秦驯,如何解決又方便用戶,又保證安全挣棕。
2)译隘、金融類、支付類App如何解決支付安全問題洛心,二維碼支付的安全問題等等固耘。
2、需求技術(shù)準(zhǔn)備
1)词身、針對本地明文存儲的安全漏洞厅目,自然是要本地進(jìn)行加密,本地加密只是增加了一些復(fù)雜度法严,但也是有效的损敷。比如利用對稱算法,通過簡單的URLENCODE + BASE64編碼防止數(shù)據(jù)明文傳輸
2)渐夸、對普通請求嗤锉、返回數(shù)據(jù),生成MD5校驗(yàn)(MD5中加入動態(tài)密鑰)墓塌,進(jìn)行數(shù)據(jù)完整性(簡單防篡改瘟忱,安全性較低,優(yōu)點(diǎn):快速)校驗(yàn)苫幢。發(fā)送請求也有PBE加密等等
3)访诱、對于重要數(shù)據(jù),使用RSA進(jìn)行數(shù)字簽名韩肝,起到防篡改作触菜。
4)、 對于比較敏感的數(shù)據(jù)哀峻,如用戶信息(登陸涡相、注冊等),客戶端發(fā)送使用RSA加密剩蟀,服務(wù)器返回使用DES(AES)加密催蝗。
類型 | 簡介 |
---|---|
本地數(shù)據(jù)加密 | 對NSUserDefaults,sqlite存儲文件數(shù)據(jù)加密育特,保護(hù)帳號和關(guān)鍵信息丙号。 |
URL編碼加密 | 對程序中出現(xiàn)的URL進(jìn)行編碼加密,防止URL被靜態(tài)分析 |
網(wǎng)絡(luò)傳輸數(shù)據(jù)加密 | 對客戶端傳輸數(shù)據(jù)提供加密方案,有效防止通過網(wǎng)絡(luò)接口的攔截獲取 |
方法體犬缨,方法名高級混淆 | 對應(yīng)用程序的方法名和方法體進(jìn)行混淆喳魏,保證源碼被逆向后無法解析代碼 |
程序結(jié)構(gòu)混排加密 | 對應(yīng)用程序邏輯結(jié)構(gòu)進(jìn)行打亂混排,保證源碼可讀性降到最低 |
三怀薛、iOS移動端安全模塊設(shè)計
1刺彩、基礎(chǔ)模塊
1)、對稱加密工具類
提供iOS客戶端的單向散列和基礎(chǔ)對稱加密算法(MD5 \ SHA \ DES \ 3DES \ RC2和RC4 \ IDEA \ DSA \ AES)
//Base64加密
+(NSString *)encodeBase64:(NSString *)input {
NSData *data = [input dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
data = [GTMBase64 encodeData:data];
NSString *base64String = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"encodeBase64 == %@",base64String);
return base64String;
}
//Base64編碼
+(NSString *)base64EncodeString:(NSString *)string {
//1.先把字符串轉(zhuǎn)換為二進(jìn)制數(shù)據(jù)
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
//2.對二進(jìn)制數(shù)據(jù)進(jìn)行base64編碼枝恋,返回編碼后的字符串
//這是蘋果已經(jīng)給我們提供的方法
NSString *str = [data base64EncodedStringWithOptions:0];
return str;
}
//Base64解密
+(NSString *)decodeBase64:(NSString *)input {
NSData *data = [input dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
data = [GTMBase64 decodeData:data];
NSString *base64String = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"decodeBase64 == %@",base64String);
return base64String;
}
//對base64編碼后的字符串進(jìn)行解碼
+(NSString *)base64DecodeString:(NSString *)string {
//1.將base64編碼后的字符串『解碼』為二進(jìn)制數(shù)據(jù)
//這是蘋果已經(jīng)給我們提供的方法
NSData *data = [[NSData alloc]initWithBase64EncodedString:string options:0];
//2.把二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為字符串返回
NSString *str = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
return str;
}
//Base64 字符串解碼成 字符串
+(NSString *)decodeBase64ToHexString:(NSString *)input {
//1.將base64編碼后的字符串『解碼』為二進(jìn)制數(shù)據(jù)
//這是蘋果已經(jīng)給我們提供的方法
NSData *myD = [[NSData alloc]initWithBase64EncodedString:input options:0];
Byte *bytes = (Byte *)[myD bytes];
//下面是Byte 轉(zhuǎn)換為16進(jìn)制迂苛。
NSString *hexStr=@"";
for(int i=0;i<[myD length];i++) {
NSString *newHexStr = [NSString stringWithFormat:@"%x",bytes[i]&0xff];///16進(jìn)制數(shù)
if([newHexStr length]==1)
hexStr = [NSString stringWithFormat:@"%@0%@",hexStr,newHexStr];
else
hexStr = [NSString stringWithFormat:@"%@%@",hexStr,newHexStr];
}
return hexStr;
}
//DES 加密
+(NSData *)encryptUseDES:(NSData *)plainText key:(Byte *)key {
NSData *textData = plainText;
NSUInteger dataLength = [textData length];
unsigned char buffer[1024];
memset(buffer, 0, sizeof(char));
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES,
kCCOptionECBMode,
key, kCCKeySizeDES,
nil,
[textData bytes], dataLength,
buffer, 1024,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
NSData *data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesEncrypted];
return data;
}
return nil;
}
//DES 解密
+(NSData *)decrypUseDES:(NSData *)plainText key:(Byte *)key {
NSData *cipherdata = plainText;
unsigned char buffer[1024];
memset(buffer, 0, sizeof(char));
size_t numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmDES,
kCCOptionECBMode,
key, kCCKeySizeDES,
nil,
[cipherdata bytes], [cipherdata length],
buffer, 1024,
&numBytesDecrypted);
if(cryptStatus == kCCSuccess) {
NSData *plaindata = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesDecrypted];
return plaindata;
}
return nil;
}
/MD5加密返回Nsdata
+(NSData *)encodeMD5:(NSData *)input {
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(input.bytes, (CC_LONG)input.length, result);
NSData *data =[[NSData alloc] initWithBytes:result length:CC_MD5_DIGEST_LENGTH];
return data;
}
如下,生成是小寫的MD5的字符串鼓择,如果要生成大寫的,只需要把
[ret appendFormat:@"%02X",result[i]];中的 "%02X"的 X改成小寫的 x即可就漾。
//MD5加密返回Nsstring
+(NSString *)MD5HexDigest:(NSData *)input {
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(input.bytes, (CC_LONG)input.length, result);
NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2];
for (int i = 0; i<CC_MD5_DIGEST_LENGTH; i++) {
[ret appendFormat:@"%02X",result[i]];
}
return ret;
}
2)呐能、非對稱加密工具類
iOS中的Security.framework提供了對RSA算法的支持。這種方式需要對密匙對進(jìn)行處理抑堡,根據(jù)public key生成證書摆出,通過private key生成p12格式的密匙。
除了Secruty.framework首妖,也可以將openssl庫編譯到iOS工程中偎漫,這可以提供更靈活的使用方式。
開源的:OpenSSLRSAWrapper
2有缆、一些場景方案設(shè)計舉例:(登錄場景token)
1)象踊、一般的登陸:
客戶端第一次發(fā)出登錄請求時, 用戶密碼以明文的方式傳輸棚壁, 一旦被截獲杯矩, 后果嚴(yán)重。因此密碼需要加密袖外,例如可采用RSA非對稱加密史隆。具體流程如下:
- 客戶端向服務(wù)器第一次發(fā)起登錄請求(不傳輸用戶名和密碼)。
- 服務(wù)器利用RSA算法產(chǎn)生一對公鑰和私鑰曼验。并保留私鑰泌射, 將公鑰發(fā)送給客戶端。
- 客戶端收到公鑰后鬓照, 加密用戶密碼熔酷, 向服務(wù)器發(fā)起第二次登錄請求(傳輸用戶名和加密后的密碼)。
- 服務(wù)器利用保留的私鑰對密文進(jìn)行解密颖杏,得到真正的密碼纯陨。
2)、token加密:
再仔細(xì)核對上述登錄流程, 我們發(fā)現(xiàn)服務(wù)器判斷用戶是否登錄翼抠, 完全依賴于sessionId, 一旦其被截獲咙轩, 黑客就能夠模擬出用戶的請求。于是我們需要引入token的概念: 用戶登錄成功后阴颖, 服務(wù)器不但為其分配了sessionId, 還分配了token活喊, token是維持登錄狀態(tài)的關(guān)鍵秘密數(shù)據(jù)。在服務(wù)器向客戶端發(fā)送的token數(shù)據(jù)量愧,也需要加密钾菊。于是一次登錄的細(xì)節(jié)再次擴(kuò)展:
- 客戶端向服務(wù)器第一次發(fā)起登錄請求(不傳輸用戶名和密碼)。服務(wù)器利用RSA算法產(chǎn)生一對公鑰和私鑰偎肃。并保留私鑰煞烫, 將公鑰發(fā)送給客戶端。
- 客戶端收到公鑰后累颂, 加密用戶密碼滞详,向服務(wù)器發(fā)送用戶名和加密后的用戶密碼; 同時另外產(chǎn)生一對公鑰和私鑰紊馏,自己保留私鑰, 向服務(wù)器發(fā)送公鑰料饥; 于是第二次登錄請求傳輸了用戶名和加密后的密碼以及客戶端生成的公鑰。
- 服務(wù)器利用保留的私鑰對密文進(jìn)行解密朱监,得到真正的密碼岸啡。 經(jīng)過判斷, 確定用戶可以登錄后赫编,生成sessionId和token巡蘸, 同時利用客戶端發(fā)送的公鑰,對token進(jìn)行加密擂送。最后將sessionId和加密后的token返還給客戶端赡若。
- 客戶端利用自己生成的私鑰對token密文解密, 得到真正的token团甲。
圖示如下:
3)逾冬、登錄保持(也就是http/https數(shù)據(jù)請求階段)
引入token后,http/https請求被獲取問題便可得到解決躺苦。 客戶端將token和其它的一些變量身腻, 利用散列加密算法得到簽名后,連同sessionId一并發(fā)送給服務(wù)器匹厘; 服務(wù)器取出保存于服務(wù)器端的token嘀趟,利用相同的法則生成校驗(yàn)簽名, 如果客戶端簽名與服務(wù)器的校驗(yàn)簽名一致愈诚, 就認(rèn)為請求來自登錄的客戶端她按。(支付寶一樣的機(jī)制)結(jié)構(gòu)圖如下:
注:token失效的兩種情況:
1牛隅、用戶登錄出系統(tǒng)
2、token在后臺的規(guī)定時間內(nèi)失效(每個token都是有時間效應(yīng)的)
失效原理:在服務(wù)器端的redis中刪除相應(yīng)key為session的鍵值對酌泰。
四媒佣、總結(jié)
本文只是初步介紹了一些加密的基礎(chǔ)知識和iOS客戶端安全設(shè)計時的基本思路,為大家提供一種參考陵刹。當(dāng)然一些金融類和支付類的App對安全性的要求更高默伍,在支付、掃碼等環(huán)節(jié)的安全設(shè)計方案可能需要更加的完善衰琐,甚至離線支付時的私鑰分端保存等等也糊,這些都是需要思考的,也希望大家給出好的建議和方案羡宙。