關於Https安全性問題、雙向驗證防止中間人攻擊問題
關於Https安全性問題、雙向驗證防止中間人攻擊問題
關於Https安全性問題、雙向驗證防止中間人攻擊問題
最近專案中遇到一個問題,安全測試時反饋出,利用fiddler擷取到了客戶端與後臺的https介面的明文內容,這是一個可怕的問題,那麼接下來我從下面幾點做一些概述和程式碼舉例。
1、Https比Http安全性?
是的,Https是以安全為目標的Http版本,在Http上使用SSL層,進行加密傳輸(對稱和非對稱加密),還具備身份驗證的功能(下面會重點說HTTPS的雙向驗證)。當然,Https是需要配置CA證書的,一般要從某些機構購買。
2、為何Https依然會被擷取?
目前的一些抓包工具,fiddler、charles使用了叫做man-in-the-middle(中間人)機制:
著作權歸作者所有。 商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
作者:連山歸藏
來源:知乎
第一步, fiddler向伺服器傳送請求進行握手, 獲取到伺服器的CA證書, 用根證書公鑰進行解密, 驗證伺服器資料簽名,獲取到伺服器CA證書公鑰。
第二步, fiddler偽造自己的CA證書, 冒充伺服器證書傳遞給客戶端瀏覽器,客戶端瀏覽器做跟fiddler一樣的事。
第三步, 客戶端瀏覽器生成https通訊用的對稱金鑰,用fiddler偽造的證書公鑰加密後傳遞給伺服器, 被fiddler截獲。
第四步, fiddler將截獲的密文用自己偽造證書的私鑰解開,獲得https通訊用的對稱金鑰。
第五步, fiddler將對稱金鑰用伺服器證書公鑰加密傳遞給伺服器, 伺服器用私鑰解開後建立信任,握手完成, 用對稱金鑰加密訊息, 開始通訊。
第六步, fiddler接收到伺服器傳送的密文, 用對稱金鑰解開,獲得伺服器傳送的明文。再次加密, 傳送給客戶端瀏覽器。
第七步, 客戶端向伺服器傳送訊息, 用對稱金鑰加密, 被fidller截獲後,解密獲得明文。
由於fiddler一直擁有通訊用對稱金鑰, 所以在整個https通訊過程中資訊對其透明。也就是說fiddler&charles向伺服器冒充是客戶端,向客戶端又謊稱自己是伺服器。
這就解釋了問什麼擷取到了Https的資料,並且,Https在傳輸過程加密,所以到了客戶端已經不是Https傳輸加密的範圍了,這個時候其實很多人都是這麼解決的,對Https資料先自己進行加密(Ex:AES、RSA),再Https傳輸,這樣即使擷取到Https資料,也看不到明文。那麼有沒有方式可以不讓fiddler&charles這種傢伙擷取到Https呢?有,就是Https的雙向驗證;
3、Https雙向驗證
伺服器端對請求它的客戶端要進行身份驗證,客戶端對自己所請求的伺服器也會做身份驗證。服務端一旦驗證到請求自己的客戶端為不可信任的,服務端就拒絕繼續通訊。客戶端如果發現服務端為不可信任的,那麼也中止通訊。具體怎麼做呢?
首先我們需要伺服器端到處證書給我們,那我公司舉例,後臺給我一個.cer檔案,我用它匯出一個.p12檔案,將這兩個匯入Xcode工程resource目錄下:
接下來,有大致三種方式來進行雙向認證:
(1)用NSURLConnection,需新增倆delegate
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace{
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
static CFArrayRef certs;
if (!certs) {
NSData*certData =[NSData dataWithContentsOfFile:[[NSBundle mainBundle]
pathForResource:@"srca" ofType:@"cer"]];
SecCertificateRef rootcert
=SecCertificateCreateWithData(kCFAllocatorDefault,CFBridgingRetain(certData));
const void *array[1] = { rootcert };
certs = CFArrayCreate(NULL, array, 1, &kCFTypeArrayCallBacks);
CFRelease(rootcert); // for completeness, really does not matter
}
SecTrustRef trust = [[challenge protectionSpace] serverTrust];
int err;
SecTrustResultType trustResult = 0;
err = SecTrustSetAnchorCertificates(trust, certs);
if (err == noErr) {
err = SecTrustEvaluate(trust,&trustResult);
}
CFRelease(trust);
BOOL trusted = (err == noErr)
&& ((trustResult == kSecTrustResultProceed)
||(trustResult == kSecTrustResultConfirm)
|| (trustResult == kSecTrustResultUnspecified));
if (trusted) {
[challenge.sender useCredential:[NSURLCredential
credentialForTrust:challenge.protectionSpace.serverTrust]
forAuthenticationChallenge:challenge];
}else{
[challenge.sender cancelAuthenticationChallenge:challenge];
}
}
- 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
/
(2)使用AFNetworking
- (void)getNBString:(void(^)(BOOL))completion
{
SecIdentityRef identity = NULL;
SecTrustRef trust = NULL;
NSString *p12 = [[NSBundle mainBundle] pathForResource:@"cc"
ofType:@"p12"];
NSData *PKCS12Data = [NSData dataWithContentsOfFile:p12];
[self extractIdentity:&identity
andTrust:&trust
fromPKCS12Data:PKCS12Data];
NSString *url = [NSString stringWithFormat:@"%@/service/GetAPPValue", kDefaultHost];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager.requestSerializer setValue:@"1"
forHTTPHeaderField:@"Platform"];
[manager.requestSerializer setValue:kAppId
forHTTPHeaderField:@"AppId"];
[manager.requestSerializer setValue:AppVersion()
forHTTPHeaderField:@"AppVersion"];
[manager.requestSerializer setValue:@"application/json"
forHTTPHeaderField:@"Accept"];
[manager.requestSerializer setValue:@"application/json"
forHTTPHeaderField:@"Content-Type"];
manager.responseSerializer.acceptableContentTypes
= [NSSet setWithArray:@[@"application/json", @"text/html"]];
manager.securityPolicy = [self customSecurityPolicy];
[manager GET:url parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
[HardCodingKeyManager getInstance].nbString = responseObject[@"Data"];
completion(YES);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"%@", error);
completion(NO);
}];
}
- (BOOL)extractIdentity:(SecIdentityRef *)outIdentity
andTrust:(SecTrustRef*)outTrust
fromPKCS12Data:(NSData *)inPKCS12Data {
OSStatus securityError = errSecSuccess;
// 證書金鑰
NSDictionary *optionsDictionary = @{@"testHttps": (__bridge id)kSecImportExportPassphrase};
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
securityError = SecPKCS12Import(
(__bridge CFDataRef)inPKCS12Data,
(__bridge CFDictionaryRef)optionsDictionary, &items);
if (securityError == 0) {
CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0);
const void *tempIdentity = NULL;
tempIdentity =
CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemIdentity);
*outIdentity = (SecIdentityRef)tempIdentity;
const void *tempTrust = NULL;
tempTrust =
CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust);
*outTrust = (SecTrustRef)tempTrust;
} else {
NSLog(@"Failed with error code %d",(int)securityError);
return NO;
}
return YES;
}
// 設定manager的AFSecurityPolicy屬性
- (AFSecurityPolicy*)customSecurityPolicy {
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"ClientC"
ofType:@"cer"];
NSData *certData = [NSData dataWithContentsOfFile:cerPath];
AFSecurityPolicy *securityPolicy =
[AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
[securityPolicy setAllowInvalidCertificates:NO]; // 記得設定為NO
NSSet *set = [NSSet setWithArray:@[certData]];
[securityPolicy setPinnedCertificates:set];
/**** SSL Pinning ****/
return securityPolicy;
}
- 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
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
/
(3)使用ASIHttpRequest
我們的專案老框架都是這種方式,苦逼的是我試了很多方法,都沒有雙向認證生效,大家有好方法,可以分享,這裡我就不貼了。
當我們配置完畢,使用charles&fiddler檢測時,https的介面都不會connect,提示證書不受信任,可能是偽伺服器之類的提示,成功。
親測,即便我們的.p12被人拿到,匯入charles&fiddler,作為它們的root certificater,只要[securityPolicy setAllowInvalidCertificates:NO]; // 記得設定為NO,依然無法connect。
相關文章
- 關於iOS HTTPS中間人攻擊iOSHTTP
- 關於值物件的驗證的問題物件
- 網站被攻擊了 該怎麼解決防止被黑客攻擊的問題網站黑客
- 自簽名證書安全性問題研究https(ssl)HTTP
- 網站存在被攻擊篡改資料的問題 該如何防止網站被攻擊網站
- SQL隱碼攻擊問題SQL
- 關於HTTP和HTTPS常見問題HTTP
- 雙向關係的LOCALCMP中的插入子表資料的問題
- 關於java安全性程式設計問題求助!!!Java程式設計
- HTTPS請求筆記- SSL安全通道驗證問題HTTP筆記
- 哈薩克對所有 HTTPS 流量發動中間人攻擊HTTP
- 急問:關於servlet中得session問題ServletSession
- https雙向認證HTTP
- 解決requests庫中SSL驗證問題
- 關於找工作時的經驗問題
- 關於FastHashMap問題ASTHashMap
- 中間人攻擊 -- Cookie噴發Cookie
- 對github的中間人攻擊Github
- 中間人攻擊 -- Cookie 噴發Cookie
- 你連 HTTPS 原理都不懂?就別講“中間人攻擊”!HTTP
- 關於IOS開發者證書過期的問題iOS
- 18、關於oracle 認證的幾個問題Oracle
- 關於時間 PHP 處理包遇到的問題時間序列化差值問題PHP
- 關於工作中遇到的問題
- 關於cuda中的函式問題函式
- 關於 iOS 10 中 ATS 的問題iOS
- 關於struts中html:errors/的問題HTMLError
- 解決ios雙擊頁面上移問題iOS
- 關於協議首部校驗和的問題協議
- 中間人攻擊原理與實踐
- SQL隱碼攻擊問題以及解決方法SQL
- Oracle 惡意攻擊問題分析和解決(一)Oracle
- 安全漏洞問題6:SQL隱碼攻擊SQL
- 關於跨域問題跨域
- 關於SQLServerDriver的問題SQLServer
- 關於JdonFramework配置問題Framework
- 關於 JavaMail 的問題JavaAI
- 關於session的問題Session