背景
? 隨著移動互聯網的普及,被越來越多的心懷不軌的人覬覦,也越來越多的安全問題暴露了出來。開發者開發出來的應用被安裝在設備上之后,用戶并不具有專業的安全知識。因此,開發者有義務為用戶的安全保駕護航,能夠為用戶提供可信賴的服務才會被其青睞。
? 攻擊者在暗,我們在明,我們不知道對方會使用怎樣的方式威脅到應用的安全。因此我先就最壞的情況來考慮,即會有人惡意去逆向我們的應用,我們應該怎么樣去應對這些可能出現的危險。
總之,黑客很厲害,關鍵是其中有很多心懷不軌的壞人,所以開發應用時講究安全很重要。
常用的逆向分析手段
要知道怎么防備,我們就需要知道一些常用的逆向分析方式,這樣才能知己知彼。通常來說分析有三種手段:
靜態分析
- 靜態分析這一階段主要會利用給各種工具,來幫助開發者分析目標軟件,常用的工具有比如Hopper、IDA、Keychain-Dumper、Class-dump等。
- 其中IDA是效果最好也是最貴的,代碼還原度很高,基本上可以照著理清楚代碼的邏輯了。
動態分析
- 動態分析是指在軟件運行的過程中進行調試分析。
- 在iOS中runtime扮演了一個很重要的角色,我們在動態分析的過程中往往也是借助了runtime的強大能力來進行的,比如我們可以動態地更改代碼的行為、可以獲取到當前的視圖層次等等。
- 這一部分我們可以利用的工具有包括Cycript、Reveal、LLDB等。
網絡分析
- 網絡分析是指利用像Charles這樣的抓包分析工具,分析應用的流量信息,安全意識比較差的公司做的一些產品我們往往能從中得到一些敏感信息。
iOS 安全手段
二進制安全
攻擊者會拿到我們的應用進行分析,然后可能會篡改我們的執行文件或者是資源文件,因此我們有必要采用一些手段來防止他們窺探以及對應用的行為進行修改.
防止調試器依附
通常黑客可能會通過gdb或者lldb來調試我們的應用以驗證代碼的行為,為后一步攻擊做準備。而調試器之所以能夠工作是因為Ptrace的存在,它為調試器提供了監控目標進程的機會。因此,通常情況下,我們在應用中禁用掉它,這可以參考我之前寫的這篇文章以及github的demo-
越獄檢測
當應用被安裝在一臺越獄后的設備之后,它所面臨的安全風險就會相對來說大很多。而可能處于安全性的考慮,可能我們并不希望我們的應用運行在這樣的環境下,因此我們可以通過一些檢測來判斷是否處在越獄的設備上。通常來說越獄設備上會安裝Cydia、MobileSubstrate等。我們可以在代碼中檢測Applications下是否有相關應用存在,如果存在就可以給用戶相應的提示并進行處理。- (BOOL)jailBreaked { if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"cydia://"]]) { return YES; } return NO; }
-
敏感字符串安全
- 編譯之后的應用中對已經初始化的字符串依然是可見的,把應用丟到IDA或者Hopper中很容易就看到一些敏感字符串的值了。
- 因此字符串的加密處理是很有必要的,比如我們可以用一些簡單的加密算法加密特別敏感的字符串,這樣初始化出來的字符串是一串不可讀的問題,需要使用的時候再進行解密。
-
混淆
- 這一步主要是為了迷惑敵人的視線,提升分析難度。編譯的時候可以通過腳本加入無意義的代碼以及將正常的字符串替換為無意義的代碼。
- 但是這樣的方式會給自己在維護的時候帶來一定困難,比如你的代碼通過混淆后發生了crash,通過dsym符號表解析出來的崩潰信息也變得不可讀了,還得對照混淆時候的映射表來查看,所以需要三思這個到底值不值得做。
- 除此之外,我們還可以混淆文件名。前幾天想逆向看看滴滴的模塊化是如何做的,無意發現了一張很有意思的圖片,后綴表示是一個圖片,但是實際上是個存有字符串的文件。我們可以用類似的方式偽裝一些相對重要的文件
敏感業務用更安全的語言
OC是一門具有動態特性的語言,這給了攻擊者很多機會去修改你原有代碼的行為,甚至是加上新的代碼。因此在核心部分可以使用更加安全的代碼,比如我們可以使用C甚至匯編去寫。往簡單來說用Swift來寫代碼都比OC一定程度上來得安全。自檢
我們可以對二進制文件或者資源文件進行md5,然后交給我們的server去比對是否來自一個合法的應用,這一定程度上也能夠提供一些防護性。
數據安全
簡單介紹
我們的應用可能會在本地存儲一系列的文件,包括用戶數據,數據庫文件,甚至在日益興起的Hybrid開發或者是各種Patch方式中我們會下載的源碼文件。我們應該盡可能地確保這些文件不會輕易被竊取到,即使竊取到了之后黑客也沒辦法使用.
-
最基礎的是我們發送網絡請求時,使用get和post方式發送請求。兩者具體區別就不做解釋了,只是引出相關安全性問題
- get:將參數暴露在外,(絕對不安全-->明文請求或者傻瓜式請求)
- post:將參數放到請求體body中,(相對于get比較安全-->但是我們可以很容易用一些軟件截獲請求數據。比如說Charles(青花瓷))
-
Charles(大部分app的數據來源都使用該工具來抓包,并做網絡測試)
注意:Charles在使用中的亂碼問題,可以顯示包內容,然后打開info.plist文件,找到java目錄下面的VMOptions,在后面添加一項:-Dfile.encoding=UTF-8
要想非常安全的傳輸數據,建議使用https。抓包不可以,但是中間人攻擊則有可能。建議雙向驗證防止中間人攻擊
-
中間人攻擊
當我們上網瀏覽網頁,從網上獲取數據的時候,我們知道,不管是http還是https協議,都是服務端被動,客戶端主動。所以,客戶端第一次發出請求之后,通常無法確定服務端是不是合法。就很可能就會出現以下情景,正常情況下,我們想要根據文章aid查看某篇文章內容,其流程如下:
查看aid=100的文章.png
但如果遭受黑客攻擊,流程就會這樣的:
這就是中間人攻擊,此時惡意服務端完全可以發起雙向攻擊:對上可以欺騙服務端,對下可以欺騙客戶端,更嚴重的是客戶端段和服務端完全感知不到已經被攻擊了。
關于中間人攻擊維基百科上有更深入的定義:
中間人攻擊(Man-in-the-middle attack,縮寫:MITM)是指攻擊者與通訊的兩端分別創建獨立的聯系,并交換其所收到的數據,使通訊的兩端認為他們正在通過一個私密的連接與對方直接對話,但事實上整個會話都被攻擊者完全控制。在中間人攻擊中,攻擊者可以攔截通訊雙方的通話并插入新的內容。在許多情況下這是很簡單的(例如,在一個未加密的Wi-Fi無線接入點的接受范圍內的中間人攻擊者,可以將自己作為一個中間人插入這個網絡)。
一個中間人攻擊能成功的前提條件是攻擊者能將自己偽裝成每一個參與會話的終端,并且不被其他終端識破。中間人攻擊是一個(缺乏)相互認證的攻擊。大多數的加密協議都專門加入了一些特殊的認證方法以阻止中間人攻擊。例如,SSL協議可以驗證參與通訊的一方或雙方使用的證書是否是由權威的受信任的數字證書認證機構頒發,并且能執行雙向身份認證。
證書鎖定可以避免中間人攻擊提高安全性
數據安全的原則
- 在網絡上不允許傳輸用戶隱私數據的明文(即:App網絡傳輸安全,指對數據從客戶端傳輸到Server中間過程的加密,防止網絡世界當中其他節點對數據的竊聽)
- 在本地不允許保存用戶隱私數據的明文(即:App數據存儲安全,主要指在磁盤做數據持久化的時候所做的加密)。
- App代碼安全(即:包括代碼混淆,加密或者app加殼
手段
-
數據保護
-
我們需要將類似用戶密碼這樣的敏感數據存到keychain中。我們還會在本地存儲多種類型的文件,其中可能會包含一些敏感信息。
使用蘋果自己的SSKeyChain鑰匙串,我們也能保證用戶的數據安全,我們將用戶的賬號信息保存到鑰匙串中能保證數據安全的原因是因為只有蘋果公司才知道鑰匙串保存在內存中的哪個位置
使用SSKeyChain我們進行下面兩步驟操作:- 在工程中加入Security.framework框架。
- 把SSKeychain.h和SSKeychain.m加到項目文件夾。
加入了需要的文件夾后,SSKeyChain的作者samsoffes在實例代碼中給出了使用SSKeyChain的方法
-
//獲取所有賬號
+ (NSArray *)allAccounts;
//通過賬號名字獲取服務名
+ (NSArray *)accountsForService:(NSString *)serviceName;
//通過服務名和賬號獲取密碼
+ (NSString *)passwordForService:(NSString*)serviceNameaccount:(NSString *)account;
//通過服務名和賬號刪除密碼
+ (BOOL)deletePasswordForService:(NSString*)serviceNameaccount:(NSString *)account;
//通過服務名和賬號設置密碼
+ (BOOL)setPassword:(NSString *)passwordforService:(NSString*)serviceName account:(NSString *)account;
-
我們在使用的時候是可以設置其訪問安全限制的。比如下面在使用FileManager的時候使用 FileProtectionType.complete 用以保證文件只有在設備未被鎖定時才可訪問。同樣在使用Keychain的時候也有類似的做法。
try? FileManager.default.setAttributes([.protectionKey: FileProtectionType.complete], ofItemAtPath: "your path ")
數據擦除
有些敏感數據我們希望用完就把它給干掉,不留一點痕跡。比如用戶在輸入密碼進行登錄的時候,我們的viewModel上有一個叫做password的property。登錄完成之后,我們即使把這個屬性置為空之后值都依然在內存當中,這個時候我們可能需要手動地把這些敏感內容給擦掉。防止鍵盤緩存
鍵盤的自動更正機制會緩存用戶的輸入,如果在一臺越獄設備上的話很可能被第三方應用輕易地讀取到緩存中的數據。
簡單來說我們可以把UITextfield的autocorrectionType屬性設置為No來關掉這個功能。在一些安全性要求較高的應用當中通常會自定義鍵盤,這樣可以防止緩存被第三方應用讀取到也能夠防止被錄屏(系統鍵盤按下有效果)
網絡安全
在網絡請求時,數據的安全性至關重要,而僅僅用 POST 請求提交用戶的隱私數據,還是不能完全解決安全問題。因此:我們經常會用到加密技術,比如說在登錄的時候,我們會先把密碼用MD5加密再傳輸給服務器或者直接對所有的參數進行加密再POST到服務器。下面是一些網絡安全手段:
不傳輸明文
我們不應該在網絡中明文傳輸敏感數據。否則即使在沒越獄的手機上,很容易遭到中間人攻擊,黑客可以輕而易舉地獲取到用戶的敏感數據
-
使用https
HTTPS(全稱:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全為目標的HTTP通道,簡單講是HTTP的安全版.- 在HTTP下加入SSL層,HTTPS的安全基礎是SSL,因此加密的詳細內容就需要SSL。 它是一個URI scheme(抽象標識符體系),句法類同http:體系。用于安全的HTTP數據傳輸。
- HTTPS的主要思想是在不安全的網絡上創建一安全信道,并可在使用適當的加密包和服務器證書可被驗證且可被信任時,對竊聽和中間人攻擊提供合理的保護
- HTTPS的信任繼承基于預先安裝在瀏覽器中的證書頒發機構(如VeriSign、Microsoft等)(意即“我信任證書頒發機構告訴我應該信任的”)
- 因此,一個到某網站的HTTPS連接可被信任,如果服務器搭建自己的https 也就是說采用自認證的方式來建立https信道,這樣一般在客戶端是不被信任的,所以我們一般在瀏覽器訪問一些https站點的時候會有一個提示,問你是否繼續
使用更安全的協議
比如我們可以使用二進制協議或者是自定義協議來提高安全性Hybrid應用安全
如今React Native、Cordova等應用得越來越廣,安全性也變得越來越重要。
在這樣的開發中,Mobile扮演的角色就是一個瀏覽器,因此在前端開發中常用的防護手段也在此使用,比如JS代碼混淆、XSS防護、加密傳輸等。
非惡意攻擊造成的安全問題
以上大部分都是一些比較惡意的針對終端用戶的攻擊防護,所謂防君子不防小人,想要搞破壞的人總是會找到辦法的。我們也還應該注意一些無意之間容易造成的安全問題。
應用退到后臺
蘋果會在應用退到后臺的時候進行截屏,會將當戶當前的狀態截圖保存下來,這可能會在無意之中造成用戶數據的泄漏,因此我們可能需要主動地替換掉這張截圖警惕iCloud備份
用戶在開啟iCloud的情況下,可能會自動對文件目錄進行自動備份,我們需要指定包含敏感信息的文件不能進行備份注意Touch ID的變化
自從iPhone有Touch ID之后大大的方便了用戶的使用,比如我們可以按一個手指就進行支付、登錄等操作。我們在開發這樣的業務邏輯的時候,應該考慮到這樣的場景,會不會因為一些正常情況下手機借給朋友造成了信息或者財產的流逝防止類似XcodeGhost事件再次發生
早前發生的XcodeGhost事件掀起了一陣波瀾,讓我們意識到,即使是非越獄設備上也可能由于疏忽造成一些安全問題,因此我們需要警惕類似的事件再次發生
數據加密的常用方式
- 常用加密算法
常用加密算法 | 名稱 | 描述 |
---|---|---|
編碼方案 | Base64 | 通過簡單 BASE64編碼 防止數據明文傳輸 |
哈希(散列)函數 | MD5(消息摘要算法)/SHA1/SHA256 | 對普通請求、返回數據,生成MD5校驗(MD5中加入動態密鑰),進行數據完整性(簡單防篡改,安全性較低,優點:快速)校驗 |
非對稱加密算法 | RSA | 對于重要數據,使用RSA進行數字簽名,起到防篡改作 |
對稱加密算法 | DES/AES | 對于比較敏感的數據,如用戶信息(登陸、注冊等),客戶端發送使用RSA加密,服務器返回使用DES(AES)加密 |
HTTPS | HTTP+SSL協議 | 要想非常安全的傳輸數據,建議使用https。抓包不可以,但是中間人攻擊則有可能。建議雙向驗證防止中間人攻擊 |
-
信息安全和相應技術對應的關系
安全算法和作用的關系圖.png
Base64
Base64簡單說明
描述:Base64可以成為密碼學的基石,非常重要。
特點:可以將任意的二進制數據進行Base64編碼
結果:所有的數據都能被編碼為并只用65個字符就能表示的文本文件。
65字符:A~Z a~z 0~9 + / =
對文件進行base64編碼后文件數據的變化:編碼后的數據~=編碼前數據的4/3,會大1/3左右。-
命令行進行Base64編碼和解碼
編碼:base64 123.png -o 123.txt 解碼:base64 123.txt -o test.png -D
-
Base64編碼原理
- 將所有字符轉化為ASCII碼;
- 將ASCII碼轉化為8位二進制;
- 將二進制3個歸成一組(不足3個在后邊補0)共24位,再拆分成4組,每組6位;
- 統一在6位二進制前補兩個0湊足8位;
- 將補0后的二進制轉為十進制;
- 從Base64編碼表獲取十進制對應的Base64編碼;
-
處理過程說明:
a.轉換的時候,將三個byte的數據,先后放入一個24bit的緩沖區中,先來的byte占高位。
b.數據不足3byte的話,于緩沖區中剩下的bit用0補足。然后,每次取出6個bit,按照其值選擇查表選擇對應的字符作為編碼后的輸出。
c.不斷進行,直到全部輸入數據轉換完成。
d.如果最后剩下兩個輸入數據,在編碼結果后加1個“=”;
e.如果最后剩下一個輸入數據,編碼結果后加2個“=”;
f.如果沒有剩下任何數據,就什么都不要加,這樣才可以保證資料還原的正確性。
g.編碼"Man"->Base64:"TWFu"
man-base64.png -
實現
a.說明: 1)從iOS7.0 開始,蘋果就提供了base64的編碼和解碼支持 2)如果是老項目,則還能看到base64編碼和解碼的第三方框架,如果當前不再支持iOS7.0以下版本,則建議替換。 b.相關代碼: //給定一個字符串,對該字符串進行Base64編碼,然后返回編碼后的結果 -(NSString *)base64EncodeString:(NSString *)string { //1.先把字符串轉換為二進制數據 NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; //2.對二進制數據進行base64編碼,返回編碼后的字符串 return [data base64EncodedStringWithOptions:0]; } //對base64編碼后的字符串進行解碼 -(NSString *)base64DecodeString:(NSString *)string { //1.將base64編碼后的字符串『解碼』為二進制數據 NSData *data = [[NSData alloc]initWithBase64EncodedString:string options:0]; //2.把二進制數據轉換為字符串返回 return [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; } c.終端測試命令 $ echo -n A | base64 $ echo -n QQ== |base64 -D
常見的加密算法和其它
- base64 編碼格式
- 密碼學演化 "秘密本"-->RSA
- 常見的加密算法
- 1)消息摘要(單向散列函數)
- 2)對稱加密
- 3)非對稱加密
- 4)證書等
哈希散列函數
-
單向散列函數的特點:
- ①加密后密文的長度是定長的
- ②如果明文不一樣,那么散列后的結果一定不一樣
- ③如果明文一樣,那么加密后的密文一定一樣(對相同數據加密,加密后的密文一樣)
- ④所有的加密算法是公開的
- ⑤不可以逆推反算
-
經典加密算法
- 1)MD5加密
- 2)SHA1
- 3)SHA512
-
MD5加密算法簡單說明
- 1)對字符串進行MD5加密可以得到一個32個字符的密文
- 2)加密之后不能根據密文逆推出明文
- 3)MD5已經被破解(暴力破解|碰撞檢測)
-
MD5加密進階
1)先加鹽,然后再進行MD5
2)先亂序,再進行MD5加密
3)亂序|加鹽,多次MD5加密等
4)使用消息認證機制,即HMAC-MD5-先對密鑰進行加密,加密之后進行兩次MD5散列
-
5)加密命令行
MD5加密-字符串 $ echo -n "520it" |md5 MD5加密-文件1 $ md5 abc.png SHA1加密: $ echo -n "520it" |openssl sha -sha1 SHA256 $ echo -n "520it" |openssl sha -sha256 SHA512 $ echo -n "520it" |openssl sha -sha512 hmacMD5加密 $ echo -n "520it" |openssl dgst -md5 -hmac "123"
散列函數應用領域
1)搜索 多個關鍵字,先對每個關鍵字進行散列,然后多個關鍵字進行或運算,如果值一致則搜索結果一致
2)版權 對文件進行散列判斷該文件是否是正版或原版的
3)文件完整性驗證 對整個文件進行散列,比較散列值判斷文件是否完整或被篡改消息認證機制(HMAC)簡單說明
1)原理
①消息的發送者和接收者有一個共享密鑰
②發送者使用共享密鑰對消息加密計算得到MAC值(消息認證碼)
③消息接收者使用共享密鑰對消息加密計算得到MAC值
④比較兩個MAC值是否一致
2)使用
①客戶端需要在發送的時候把(消息)+(消息·HMAC)一起發送給服務器
②服務器接收到數據后,對拿到的消息用共享的KEY進行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"]);
MD5認證圖解
對稱加密
-
對稱加密的特點
1)加密/解密使用相同的密鑰
2)加密和解密的過程是可逆的(明文->密文->明文)
對稱加密算法圖解.png -
經典算法
1)DES 數據加密標準
2)3DES 使用3個密鑰,對消息進行(密鑰1·加密)+(密鑰2·解密)+(密鑰3·加密)
3)AES 高級加密標準 -
分組密碼簡單說明
密碼算法可以分為分組密碼和流密碼兩種。
-
分組密碼:每次只能處理特定長度的一組數據的一類密碼算法。一個分組的比特數量就稱之為分組長度。
DES和3DES的分組長度都是64比特。即每次只能加密64比特的明文,并生成64比特的密文。AES的分組長度有128比特、192比特和256比特可以選擇。
流密碼:對數據流進行連續處理的一類算法。流密碼中一般以1比特、8比特或者是32比特等作為單位倆進行加密和解密。
-
ECB分組模式
ECB模式的全稱為Electronic CodeBook模式。又成為電子密碼本模式。
特點:- 1)使用ECB模式加密的時候,相同的明文分組會被轉換為相同的密文分組。
- 2)類似于一個巨大的明文分組->密文分組的對照表。
-
CBC分組模式
CBC模式全稱為Cipher Block Chainning模式(密文分組鏈接模式|電子密碼鏈條)
特點:在CBC模式中,首先將明文分組與前一個密文分組進行XOR運算,然后再進行加密
終端測試命令:
加密 $ openssl enc -des-ecb -K 616263 -nosalt -in 123.txt -out 123.bin
解密 $ openssl enc -des-ecb -K 616263 -nosalt -in 123.bin -out 1231.txt -d
- 簡單示例
/**
* 加密字符串并返回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]);
非對稱加密RSA
-
非對稱加密的特點
- 1)使用公鑰加密,使用私鑰解密
- 2)公鑰是公開的,私鑰保密
- 3)加密處理安全,但是性能極差
-
經典算法---RSA
- RSA 原理
- (1)求N,準備兩個質數p和q,N = p x q
- (2)求L,L是p-1和q-1的最小公倍數。L = lcm(p-1,q-1)
- (3)求E,E和L的最大公約數為1(E和L互質)
- (4)求D,E x D mode L = 1
- RSA加密小實踐
- (1)p = 17,q = 19 =>N = 323
- (2)lcm(p-1,q-1)=>lcm(16,18)=>L= 144
- (3)gcd(E,L)=1 =>E=5
- (4)E乘以幾可以mode L =1? D=29可以滿足
- (5)得到公鑰為:E=5,N=323
- (6)得到私鑰為:D=29,N=323
- (7)加密 明文的E次方 mod N = 123的5次方 mod 323 = 225(密文)
- (8)解密 密文的D次方 mod N = 225的29次方 mod 323 = 123(明文)
- RSA 原理
**openssl生成密鑰命令**
生成強度是 512 的 RSA 私鑰:`$ openssl genrsa -out private.pem 512`
以明文輸出私鑰內容:`$ openssl rsa -in private.pem -text -out private.txt`
校驗私鑰文件:`$ openssl rsa -in private.pem -check`
從私鑰中提取公鑰:`$ openssl rsa -in private.pem -out public.pem -outform PEM -pubout`
以明文輸出公鑰內容:`$ openssl rsa -in public.pem -out public.txt -pubin -pubout -text`
使用公鑰加密小文件:`$ openssl rsautl -encrypt -pubin -inkey public.pem -in msg.txt -out msg.bin`
使用私鑰解密小文件:`$ openssl rsautl -decrypt -inkey private.pem -in msg.bin -out a.txt`
將私鑰轉換成 DER 格式:`$ openssl rsa -in private.pem -out private.der -outform der`
將公鑰轉換成 DER 格式:`$ openssl rsa -in public.pem -out public.der -pubin -outform der`
- 簡單示例
// 公鑰加密時調用類方法:
+ (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);
數字簽名
-
數字簽名的應用場景
答:需要嚴格驗證發送方身份信息情況 -
數字簽名原理
- 1)客戶端處理
- ①對"消息"進行 HASH 得到 "消息摘要"
- ②發送方使用自己的私鑰對"消息摘要" 加密(數字簽名)
- ③把數字簽名附著在"報文"的末尾一起發送給接收方
- 2)服務端處理
- ①對"消息" HASH 得到 "報文摘要"
- ②使用公鑰對"數字簽名" 解密
- ③對結果進行匹配
- 1)客戶端處理
數字證書
簡單說明
證書和駕照很相似,里面記有姓名、組織、地址等個人信息,以及屬于此人的公鑰,并有認證機構施加數字簽名,只要看到公鑰證書,我們就可以知道認證機構認證該公鑰的確屬于此人-
數字證書的內容
- 1)公鑰
- 2)認證機構的數字簽名
-
證書的生成步驟
- 1)生成私鑰
openssl genrsa -out private.pem 1024
- 2)創建證書請求
openssl req -new -key private.pem -out rsacert.csr
- 3)生成證書并簽名,有效期10年
openssl x509 -req -days 3650 -in rsacert.csr -signkey private.pem -out rsacert.crt
- 4)將 PEM 格式文件轉換成 DER 格式
openssl x509 -outform der -in rsacert.crt -out rsacert.der
- 5)導出P12文件
openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt
- 1)生成私鑰
-
iOS開發中的注意點
- 1)在iOS開發中,不能直接使用 PEM 格式的證書,因為其內部進行了Base64編碼,應該使用的是DER的證書,是二進制格式的
- 2)OpenSSL默認生成的都是PEM格式的證書
-
證書鎖定的缺點
- 證書鎖定盡管帶了較高的安全性,但是這種安全性的提高卻犧牲了靈活性。一旦當證書發生變化時,我們的客戶端也必須隨之升級,除此之外,我們的服務端不得不為了兼容以前的客戶端而做出一些妥協或者說直接停用以前的客戶端,這對開發者和用戶來說并不是那么的友好。
- 但實際上,極少情況下我們才會變動證書。因此,如果產品安全性要求比較高還是啟動證書鎖定吧。
- 在iOS開發中,我們可以自己給自己簽發數字證書,就類似于12306購票網站。從而保證了數據的安全性。
使用Https
-
https簡單說明
- HTTPS(全稱:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全為目標的HTTP通道,簡單講是HTTP的安全版。
- 即HTTP下加入SSL層,HTTPS的安全基礎是SSL,因此加密的詳細內容就需要SSL。 它是一個URI scheme(抽象標識符體系),句法類同http:體系。用于安全的HTTP數據傳輸。
- https:URL表明它使用了HTTP,但HTTPS存在不同于HTTP的默認端口及一個加密/身份驗證層(在HTTP與TCP之間)。
-
HTTPS和HTTP的區別主要為以下四點:
- 一、https協議需要到ca申請證書,一般免費證書很少,需要交費。
- 二、http是超文本傳輸協議,信息是明文傳輸,https 則是具有安全性的ssl加密傳輸協議。
- 三、http和https使用的是完全不同的連接方式,用的端口也不一樣,前者是80,后者是443。
- 四、http的連接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。
-
簡單說明
- 1)HTTPS的主要思想是在不安全的網絡上創建一安全信道,并可在使用適當的加密包和服務器證書可被驗證且可被信任時,對竊聽和中間人攻擊提供合理的保護。
- 2)HTTPS的信任繼承基于預先安裝在瀏覽器中的證書頒發機構(如VeriSign、Microsoft等)(意即“我信任證書頒發機構告訴我應該信任的”)。
- 3)因此,一個到某網站的HTTPS連接可被信任,如果服務器搭建自己的https 也就是說采用自認證的方式來建立https信道,這樣一般在客戶端是不被信任的。
- 4)所以我們一般在瀏覽器訪問一些https站點的時候會有一個提示,問你是否繼續。
-
對開發的影響。
- 1、如果是自己使用NSURLSession來封裝網絡請求,涉及代碼如下。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]]; NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.apple.com"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); }]; [task resume]; } /* 只要請求的地址是HTTPS的, 就會調用這個代理方法 我們需要在該方法中告訴系統, 是否信任服務器返回的證書 Challenge: 挑戰 質問 (包含了受保護的區域) protectionSpace : 受保護區域 NSURLAuthenticationMethodServerTrust : 證書的類型是 服務器信任 */ - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler { // NSLog(@"didReceiveChallenge %@", challenge.protectionSpace); NSLog(@"調用了最外層"); // 1.判斷服務器返回的證書類型, 是否是服務器信任 if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { NSLog(@"調用了里面這一層是服務器信任的證書"); /* NSURLSessionAuthChallengeUseCredential = 0, 使用證書 NSURLSessionAuthChallengePerformDefaultHandling = 1, 忽略證書(默認的處理方式) NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2, 忽略書證, 并取消這次請求 NSURLSessionAuthChallengeRejectProtectionSpace = 3, 拒絕當前這一次, 下一次再詢問 */ // NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; NSURLCredential *card = [[NSURLCredential alloc]initWithTrust:challenge.protectionSpace.serverTrust]; completionHandler(NSURLSessionAuthChallengeUseCredential , card); } }
- 2、如果使用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); }];
-
ATS
- iOS9中新增App Transport Security(簡稱ATS)特性, 讓原來請求時候用到的HTTP,全部都轉向TLS1.2協議進行傳輸。
- 這意味著所有的HTTP協議都強制使用了HTTPS協議進行傳輸。
- 如果我們在iOS9下直接進行HTTP請求是會報錯。系統會告訴我們不能直接使用HTTP進行請求,需要在Info.plist中控制ATS的配置。
- "NSAppTransportSecurity"是ATS配置的根節點,配置了節點表示告訴系統要走自定義的ATS設置。
- "NSAllowsAritraryLoads"節點控制是否禁用ATS特性,設置YES就是禁用ATS功能;
- 采用解決方法,修改配置信息。
* ATS默認的條件
* 1)服務器TLS版本至少是1.2版本
* 2)連接加密只允許幾種先進的加密
* 3)證書必須使用SHA256或者更好的哈希算法進行簽名,要么是2048位或者更長的RSA密鑰,要么就是256位或更長的ECC密鑰。
* AFSecurityPolicy,內部有三個重要的屬性,如下:
* AFSSLPinningMode SSLPinningMode; //該屬性標明了AFSecurityPolicy是以何種方式來驗證
* BOOL allowInvalidCertificates; //是否允許不信任的證書通過驗證,默認為NO
* BOOL validatesDomainName; //是否驗證主機名,默認為YES
```
"AFSSLPinningMode"枚舉類型有三個值,分別是AFSSLPinningModeNone、AFSSLPinningModePublicKey、AFSSLPinningModeCertificate。
"AFSSLPinningModeNone"代表了AFSecurityPolicy不做更嚴格的驗證,"只要是系統信任的證書"就可以通過驗證,不過,它受到allowInvalidCertificates和validatesDomainName的影響;
"AFSSLPinningModePublicKey"是通過"比較證書當中公鑰(PublicKey)部分"來進行驗證,通過SecTrustCopyPublicKey方法獲取本地證書和服務器證書,然后進行比較,如果有一個相同,則通過驗證,此方式主要適用于自建證書搭建的HTTPS服務器和需要較高安全要求的驗證;
"AFSSLPinningModeCertificate"則是直接將本地的證書設置為信任的根證書,然后來進行判斷,并且比較本地證書的內容和服務器證書內容是否相同,來進行二次判斷,此方式適用于較高安全要求的驗證。
如果HTTPS服務器滿足ATS默認的條件,而且SSL證書是通過權威的CA機構認證過的,那么什么都不用做。如果上面的條件中有任何一個不成立,那么都只能修改ATS配置。
```
-
HTTP 和HTTPS的區別
- HTTP:當客戶端發送請求,那么服務器會直接返回數據.
* HTTPS:當客戶端第一次發送請求的時候,服務器會返回一個包含公鑰的受保護空間(也成為證書),當我們發送請求的時候,公鑰會將請求加密再發送給服務器,服務器接到請求之后,用自帶的私鑰進行解密,如果正確再返回數據。這就是 HTTPS 的安全性所在。