盡管Https協議能夠提供數據的加密、身份的認證等安全服務,但並不是沒有漏洞。HTTPS協議安全隱患的存在可能使用戶受到各種極具破壞力的網絡攻擊。其中中間人攻擊(Man In The Middle, MITM)就是非常危險的一種攻擊方式。
場景分析:假設用戶手機接入了不安全的wifi,這時發生了dns被篡改的情況。如用戶訪問了Https://www.taobao.com, 被跳轉到了類似淘寶的釣魚站點,且該站點用的是真實ca證書,這時用戶的賬戶安全將受到巨大威脅。
這里介紹一個ios中能大大降低此類風險的做法,即公鑰證書匹配。
1. 在終端執行,openssl s_client -connect www.taobao.com:443 -showcerts ,獲取公鑰內容。
0 s:/C=CN/ST=ZheJiang/L=HangZhou/O=Alibaba (China) Technology Co., Ltd./CN=*.tmall.com i:/C=BE/O=GlobalSign nv-sa/CN=GlobalSign Organization Validation CA - G2 -----BEGIN CERTIFICATE----- MIIGqzCCBZOgAwIBAgISESHmhyz9S+Hphge+SQIlaA0ZMA0GCSqGSIb3DQEBBQUA MF0xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMTMwMQYD VQQDEypHbG9iYWxTaWduIE9yZ2FuaXphdGlvbiBWYWxpZGF0aW9uIENBIC0gRzIw HhcNMTUwNjI2MDY1NzA0WhcNMTUxMjI2MTU1OTU5WjB4MQswCQYDVQQGEwJDTjER MA8GA1UECBMIWmhlSmlhbmcxETAPBgNVBAcTCEhhbmdaaG91MS0wKwYDVQQKEyRB bGliYWJhIChDaGluYSkgVGVjaG5vbG9neSBDby4sIEx0ZC4xFDASBgNVBAMMCyou dG1hbGwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp1c2CDm6 I6V8W7h1NnvnZz02NzRnMd/rqimdeqERgsZV192GRo5gwnyCgulZePcXFJSdpv82 uZHnr1Ya83SX8vhxNzEyFkk3KCLPfkSbNbOOkWfQGwKCNPmDlPbM+rxBN8sdaCGV /oLptOanTzabS3oj0eFW9ePq7uOcuM2/Sppn9BCGRUBj+8cP0KVmpPLbR3a0/SpZ TDWJRssb7wV/Vjsvk3JFR9g/frjllH+pO+EaWo4XFVcHMjL8I4PJGDUFZDbm3eYw RzclOzWMlyEgb+moSyJKPisjv2mxkmbHIN50wsKfclBamWFDNIfsPX3zk/OcRr/5 v4pqbTWPBSauxwIDAQABo4IDSDCCA0QwDgYDVR0PAQH/BAQDAgWgMEkGA1UdIARC MEAwPgYGZ4EMAQICMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNp Z24uY29tL3JlcG9zaXRvcnkvMIIBmwYDVR0RBIIBkjCCAY6CCyoudG1hbGwuY29t gg8qLmx3LmFsaWltZy5jb22CDCoudGFvYmFvLmNvbYIOKi5tLnRhb2Jhby5jb22C DSoubS50bWFsbC5jb22CCiouMTY4OC5jb22CDyoueWFvLjk1MDk1LmNvbYIRKi5t Lnlhby45NTA5NS5jb22CCioudG1hbGwuaGuCDCoubS50bWFsbC5oa4INKi5hbGl0 cmlwLmNvbYIKKi5ldGFvLmNvbYIMKi5hbGl5dW4uY29tgg8qLmp1aHVhc3Vhbi5j b22CEiouYWxpcWluLnRtYWxsLmNvbYIPKi5qdS50YW9iYW8uY29tghIqLmNoaW5h LnRhb2Jhby5jb22CDiouM2MudG1hbGwuY29tghEqLnRyaXAudGFvYmFvLmNvbYIQ Ki5mb29kLnRtYWxsLmNvbYIPKi5qaWEudG1hbGwuY29tghAqLmppYS50YW9iYW8u Y29tgg8qLmNoaS50bWFsbC5jb22CECouY2hpLnRhb2Jhby5jb22CCXRtYWxsLmNv bTAJBgNVHRMEAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBFBgNV HR8EPjA8MDqgOKA2hjRodHRwOi8vY3JsLmdsb2JhbHNpZ24uY29tL2dzL2dzb3Jn YW5pemF0aW9udmFsZzIuY3JsMIGWBggrBgEFBQcBAQSBiTCBhjBHBggrBgEFBQcw AoY7aHR0cDovL3NlY3VyZS5nbG9iYWxzaWduLmNvbS9jYWNlcnQvZ3Nvcmdhbml6 YXRpb252YWxnMi5jcnQwOwYIKwYBBQUHMAGGL2h0dHA6Ly9vY3NwMi5nbG9iYWxz aWduLmNvbS9nc29yZ2FuaXphdGlvbnZhbGcyMB0GA1UdDgQWBBQHw4CCRIGhjNjl 3r4fH4troxWe7zAfBgNVHSMEGDAWgBRdRrKNxEt0HLvt9XO2Orc4j3WefjANBgkq hkiG9w0BAQUFAAOCAQEALXJXHszy4jjNs5KbovH5wv6trqdXz02fEo5hpV0/UCXI Eyk3Glm+4376kCTordj64YEIe05G+URVG3MlBI/webk6P6lrVTdHv+ihwLcvJah5 A3u7xXcay53KV/j2tkRc5CaP/ifCndoGL+Z22qQdLeckY/ArS3xrP76bBOQF8k6U gM1+iZWbL59wmRPwYBVrGqIhn+Gcb7PGJmyS/PaxL+hu/w3EKH9Yos10Xd+L367c 8sdNQhRFBxCuiIrvW7IW6GAoZRd0dU+e6gGc/QUfoE8RQ3m8XISZwb9g0mKbt0aG idQ75IPLfSgMiRy6o9PG4l3Y+d9G1ch+SFIidvmlrA== -----END CERTIFICATE-----
2. 將公鑰內容(-----BEGIN CERTIFICATE----- 至-----END CERTIFICATE-----)保存成.PEM格式文件。
3. 執行命令 openssl x509 -inform PEM -outform DER -in cert.pem -out cert.der , 將.pem證書轉換成.der格式。
4. 在app工程中,導入生成好的.der證書。
5. 在實現UIWebViewDelegate 的View Controller.h中添加
@interface TargetViewController : UIViewController<UIWebViewDelegate, NSURLConnectionDelegate, NSURLConnectionDataDelegate>
6. 在init方法中添加讀取證書的邏輯,並存到self.trustedCerts數組中
//讀取ssl證書信息
if (!hasReadLocalCerts) { certsFile = [NSMutableArray arrayWithObjects: @"taobao.com.der", nil]; self.trustedCerts = [NSMutableArray array]; for (NSString *file in certsFile) { NSString *fpath = [[NSBundle mainBundle] pathForResource:file ofType:@"der"]; NSData * cerData = [NSData dataWithContentsOfFile:fpath]; SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(cerData)); [self.trustedCerts addObject:CFBridgingRelease(certificate)]; } hasReadLocalCerts = YES; }
7. 在
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType
方法中添加https站點的處理邏輯:
NSURL *url = [request URL]; NSString *schema = [[url scheme] lowercaseString];
//未有過證書驗證,將失敗的請求紀錄下來 if ([schema isEqualToString:@"https"]){ if (!authenticated) { NSLog(@"Authenticated failed!"); [self.webView stopLoading]; failedRequest = request; [[[NSURLConnection alloc] initWithRequest:request delegate:self] start] ; return NO; } return YES; }
8. 實現證書驗證
#pragma mark ------ NSURLConnectionDelegate
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{ NSLog(@"Check ssl cert."); //獲取trust object
SecTrustRef trust = challenge.protectionSpace.serverTrust; SecTrustResultType result; //這里將之前導入的證書設置成下面驗證的Trust Object的anchor certificate
SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)self.trustedCerts); //SecTrustEvaluate會查找前面SecTrustSetAnchorCertificates設置的證書或者系統默認提供的證書,對trust進行驗證
OSStatus status = SecTrustEvaluate(trust, &result); if (status == errSecSuccess && (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified)) { //驗證成功,生成NSURLCredential憑證cred,告知challenge的sender使用這個憑證來繼續連接
NSURLCredential *cred = [NSURLCredential credentialForTrust:trust]; [challenge.sender useCredential:cred forAuthenticationChallenge:challenge]; NSLog(@"SSL cert match!"); } else { //驗證失敗,取消這次驗證流程
[challenge.sender cancelAuthenticationChallenge:challenge]; NSLog(@"SSL cert missmatch!"); } [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; }
#pragma mark ------ NSURLConnectionDataDelegate
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)pResponse { authenticated = YES; [connection cancel];
//驗證通過,繼續執行之前被攔截下來的請求 [self.webView loadRequest:failedRequest]; }
轉載請注明:
