HTTPS的學習總結
HTTPS學習總結
簡述
HTTPS對比HTTP就多了一個安全層SSL/TLS,具體就是驗證服務端的證書和對內容進行加密。
先來看看HTTP和HTTPS的區別
我用AFN訪問http下的httpbin.org/image/png
然后用Charles抓一下包,可以看到傳輸的圖片 
然后訪問HTTPS下的https://httpbin.org/image/png
再抓包,看到數據是亂碼,這就是加密過后的數據 
關於加密算法
1)對稱加密:密鑰只有一個,加密解密為同一個密碼,且加解密速度快,典型的對稱加密算法有DES、AES等;
2)非對稱加密:非對稱加密算法需要兩個密鑰:公開密鑰(publickey)和私有密鑰(privatekey)。公開密鑰與私有密鑰是一對,如果用公開密鑰對數據進行加密,只有用對應的私有密鑰才能解密;如果用私有密鑰對數據進行加密,那么只有用對應的公開密鑰才能解密。因為加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法。
過程就像我們用github的時候也是這樣,我們電腦這里生成私鑰和公鑰,公鑰上傳到github,私鑰添加到我們電腦的ssh里,這樣github給我們傳輸數據就是用我們上傳的公鑰來加密,我們獲得數據后會用私鑰去解密。
什么是SSL/TLS
TLS是 Transport Layer Security的縮寫,傳輸層安全性協議,SSL是Secure Sockets Layer的縮寫,安全sokects層協議。SSL/TLS有很多好處,強大的驗證,算法靈活,容易部署和使用。缺點是增加處理器的負擔,但是消耗的性能很小,對比安全性來說可以忽略不計。
通信過程
通信過程有四次握手。
1、客戶端發送請求,服務器返回公鑰給客戶端;
2、客戶端生成對稱加密秘鑰,用公鑰對其進行加密后,返回給服務器;
3、服務器收到后,利用私鑰解開得到對稱加密秘鑰,保存;
4、之后的交互都使用對稱加密后的數據進行交互。
HTTPS通信的優點
1)客戶端產生的密鑰只有客戶端和服務器端能得到;
2)加密的數據只有客戶端和服務器端才能得到明文;
3)客戶端到服務端的通信是安全的。
如何獲得證書
1.向CA申請證書
電子商務認證授權機構(CA, Certificate Authority),也稱為電子商務認證中心,是負責發放和管理數字證書的權威機構。
這里就不細說了。
2.自制證書
還有一種方式就是自制證書,自制證書的證書是用OpenSSL生成的。OpenSSL 是一個強大的安全套接字層密碼庫,囊括主要的密碼算法、常用的密鑰和證書封裝管理功能及SSL協議,並且已經在github上開源。
OpenSSL的各種指令 
自制證書的命令是
|
1
|
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days XXX
|
剛開始輸入命令就會自動生成key.pem
輸入命令后會讓你輸入密碼、國家、省市、組織(公司)、名字等信息
輸入完成便會生成證書cert.pem
關於命令的一些選項:
- req 是證書請求和生成的程序
- -x509 一種證書標准
- -newkey arg,arg是參數,例如rsa:2048是指生成2048位的rsa key
- -keyout filename 輸出的根證書文件名
- -out filename 輸出的標准證書文件嗎
- -day n 用X.509標准的話要指定驗證多少天,默認30 *
預覽cert.pem可以看到剛才輸入的信息 
pem可以轉換成cer格式,可以用命令
|
1
|
openssl x509 -in <你的服務器證書>.pem -outform der -out server.cer
|
也可以雙擊 cert.pem,這樣是導入到鑰匙串,打開鑰匙串便可導出cer格式的證書。
以上 部分自制證書資料參考的是stackoverflow的這個問題
關於Security框架
看了一下蘋果的官方文檔,Security框架是C語言寫的,提供了一些管理標識碼,證書,數字簽名,信任等的API。
這里介紹一下幾個常用的對象。SecIdentityRef 代碼一個標識碼對象,struct類型,包含一個SecKeyRef類型和一個SecCertificateRef類型。SecKeyRef就是一個非對稱的key對象。SecCertificateRef是一個遵循X.509標准的證書對象。如果這兩個對象沒有存儲到keychain中,則會把它們轉換成SecKeychainItemRef對象還會使Keychain Services的函數返回錯誤。
要生成p12證書,這讓我想起配置推送證書的時候,導出證書的時候便是把cer格式的證書轉換成p12格式的證書。
iOS實現HTTPS傳輸
因為項目都是用AFN,所以就大概說下AFN的實現方法
如果是CA認證的證書,則直接用AFN請求便可。
|
1
2
3
4
5
6
7
8
9
10
11
|
AFSecurityPolicy * securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
//allowInvalidCertificates 是否允許無效證書(也就是自建的證書),默認為NO
//如果是需要驗證自建證書,需要設置為YES
securityPolicy.allowInvalidCertificates =
YES
;
//validatesDomainName 是否需要驗證域名,默認為YES;
//假如證書的域名與你請求的域名不一致,需把該項設置為NO;如設成NO的話,即服務器使用其他可信任機構頒發的證書,也可以建立連接,這個非常危險,建議打開。
//置為NO,主要用於這種情況:客戶端請求的是子域名,而證書上的是另外一個域名。因為SSL證書上的域名是獨立的,假如證書上注冊的域名是www.google.com,那么mail.google.com是無法驗證通過的;當然,有錢可以注冊通配符的域名*.google.com,但這個還是比較貴的。
//如置為NO,建議自己添加對應域名的校驗邏輯。
securityPolicy.validatesDomainName =
YES
;
|
如果是自制證書,則客戶端需要導入服務端的公鑰,把公鑰拖進Xocde里,這里要用到把證書從pem轉換成p12格式,參見上面的方法
2.修改驗證方式
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
- (
void
)testClientCertificate {
SecIdentityRef identity =
NULL
;
SecTrustRef trust =
NULL
;
NSString
*p12 = [[
NSBundle
mainBundle] pathForResource:@
"testClient"
ofType:@
"p12"
];
NSData
*PKCS12Data = [
NSData
dataWithContentsOfFile:p12];
[[
self
class
] extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data];
NSDictionary
*dic = @{@
"request"
: @{
@
"orderNo"
: @
"1409282102222110030643"
,
@
"type"
: @(2)
}
};
_signString =
nil
;
NSData
*postData = [
NSJSONSerialization
dataWithJSONObject:dic
options:
NSJSONWritingPrettyPrinted
error:
nil
];
NSString
*sign = [
self
signWithSignKey:@
"test"
params:dic];
NSMutableData
*body = [postData mutableCopy];
NSLog
(@
"%@"
, [[
NSString
alloc] initWithData:body encoding:
NSUTF8StringEncoding
]);
url = [
NSString
stringWithFormat:url, sign];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager.requestSerializer setValue:@
"application/json"
forHTTPHeaderField:@
"Accept"
];
[manager.requestSerializer setValue:@
"application/json"
forHTTPHeaderField:@
"Content-Type"
];
manager.responseSerializer.acceptableContentTypes = [
NSSet
setWithArray:@[@
"application/json"
,
@
"text/plain"
]];
manager.securityPolicy = [
self
customSecurityPolicy];
[manager POST:url parameters:dic success:^(AFHTTPRequestOperation *operation,
id
responseObject) {
NSLog
(@
"JSON: %@"
, responseObject);
} failure:^(AFHTTPRequestOperation *operation,
NSError
*error) {
NSLog
(@
"Error: %@"
, error);
}];
}
// 下面這段代碼是處理SSL安全性問題的:
/**** SSL Pinning ****/
- (AFSecurityPolicy*)customSecurityPolicy {
NSString
*cerPath = [[
NSBundle
mainBundle] pathForResource:@
"testClient"
ofType:@
"cer"
];
NSData
*certData = [
NSData
dataWithContentsOfFile:cerPath];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy defaultPolicy];
[securityPolicy setAllowInvalidCertificates:
YES
];
[securityPolicy setPinnedCertificates:@[certData]];
[securityPolicy setSSLPinningMode:AFSSLPinningModeCertificate];
/**** SSL Pinning ****/
return
securityPolicy;
}
|
這段代碼來自參考資料3,寫的很好,沒必要再說一次了
總結
在現在網絡越來越發達的情況下,安全性越來越重要。不多說,https是趨勢。
參考資料:
1.聊聊 iOS 中的網絡加密 / 滕先洪
2.iOS安全系列之一:HTTPS / Jaminzzhang
3.iOS訪問HTTPS SSL和TLS雙向加密 / 標哥的技術博客
4.蘋果相關官方文檔
