iOS https 雙向認證


//點擊請求數(shù)據(jù)
- (void)btnAction{

NSString*urlString=@"https://192.168.30.91/";

AFSecurityPolicy*securityPolicy = [AFSecurityPolicypolicyWithPinningMode:AFSSLPinningModeNone];

//是否允許,NO--不允許無效的證書...

//因為大多數(shù)都是自己給自己頒布的證書,對于蘋果來說是不被信任的,是無效的,所以要設(shè)置YES.

securityPolicy.allowInvalidCertificates=YES;

//設(shè)置證書如果不設(shè)置,可以自動讀取工程里的cer文件

// 1.zhengshu.cer ca.cer(一個是服務(wù)器證書,一個服務(wù)器CA根證書,哪一個都可以)

//service.cer 2.服務(wù)器證書

//securityPolicy.pinnedCertificates=set;

//validatesDomainName是否需要驗證域名映之,默認為YES谚殊;

//假如證書的域名與你請求的域名不一致芥永,需把該項設(shè)置為NO奄侠;如設(shè)成NO的話,即服務(wù)器使用其他可信任機構(gòu)頒發(fā)的證書迷雪,也可以建立連接限书,這個非常危險,建議打開章咧。

//置為NO倦西,主要用于這種情況:客戶端請求的是子域名,而證書上的是另外一個域名慧邮。因為SSL證書上的域名是獨立的调限,假如證書上注冊的域名是www.google.com,那么mail.google.com是無法驗證通過的误澳;當(dāng)然,有錢可以注冊通配符的域名*.google.com秦躯,但這個還是比較貴的忆谓。

//如置為NO,建議自己添加對應(yīng)域名的校驗邏輯踱承。

//一.zhengshu.cer[https://192.168.30.91/](https://192.168.30.91/)無需設(shè)置infoplist

//二.service.cer[https://192.168.30.55:8443/IEMS_APP/](https://192.168.30.55:8443/IEMS_APP/)//模擬器必須設(shè)置info.plist YES真機不用設(shè)置info.plist

//兩種都可以加密數(shù)據(jù)安全,防止中間人抓包工具

securityPolicy.validatesDomainName=NO;

AFHTTPSessionManager* manager = [AFHTTPSessionManagermanager];

manager.responseSerializer.acceptableContentTypes=[NSSetsetWithObjects:@"text/html",nil];

manager.requestSerializer.cachePolicy=NSURLRequestReloadIgnoringLocalCacheData;

__weaktypeof(self)weakSelf =self;

//重寫這個方法就能提供客戶端驗證

[managersetSessionDidBecomeInvalidBlock:^(NSURLSession*_Nonnullsession,NSError*_Nonnullerror) {

        NSLog(@"setSessionDidBecomeInvalidBlock");

}];

[managersetSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession*session,NSURLAuthenticationChallenge*challenge,NSURLCredential*__autoreleasing*_credential) {

NSURLSessionAuthChallengeDispositiondisposition =NSURLSessionAuthChallengePerformDefaultHandling;

    __autoreleasingNSURLCredential*credential =nil;

    if([challenge.protectionSpace.authenticationMethodisEqualToString:NSURLAuthenticationMethodServerTrust]) {

         if([manager.securityPolicyevaluateServerTrust:challenge.protectionSpace.serverTrustforDomain:challenge.protectionSpace.host]) {

                credential = [NSURLCredentialcredentialForTrust:challenge.protectionSpace.serverTrust];

                if(credential) {

                        disposition =NSURLSessionAuthChallengeUseCredential;

                }else{

                        disposition =NSURLSessionAuthChallengePerformDefaultHandling;

          }
  }else{

        disposition =NSURLSessionAuthChallengeCancelAuthenticationChallenge;

}

}else{

// client authentication

SecIdentityRefidentity =NULL;

SecTrustReftrust =NULL;

NSString*p12 = [[NSBundlemainBundle]pathForResource:@"client.key"ofType:@"p12"];

NSFileManager*fileManager =[NSFileManagerdefaultManager];

if(![fileManagerfileExistsAtPath:p12])

{

NSLog(@"client.p12:not exist");

}

else

{

NSData*PKCS12Data = [NSDatadataWithContentsOfFile:p12];

if([[weakSelfclass]extractIdentity:&identityandTrust:&trustfromPKCS12Data:PKCS12Data])

{

SecCertificateRefcertificate =NULL;

SecIdentityCopyCertificate(identity, &certificate);

constvoid*certs[] = {certificate};

CFArrayRefcertArray =CFArrayCreate(kCFAllocatorDefault, certs,1,NULL);

credential =[NSURLCredentialcredentialWithIdentity:identitycertificates:(__bridgeNSArray*)certArraypersistence:NSURLCredentialPersistencePermanent];

disposition =NSURLSessionAuthChallengeUseCredential;

}

}

}

*_credential = credential;

returndisposition;

}];

manager.securityPolicy= securityPolicy;

manager.responseSerializer= [AFHTTPResponseSerializerserializer];

[managerGET:urlStringparameters:nilprogress:^(NSProgress*_NonnulldownloadProgress) {

}success:^(NSURLSessionDataTask*_Nonnulltask,id_NullableresponseObject) {

NSString*html=[[NSStringalloc]initWithData:responseObjectencoding:NSUTF8StringEncoding];

self.label.text=html;

}failure:^(NSURLSessionDataTask*_Nullabletask,NSError*_Nonnullerror) {

self.label.textColor=[UIColorredColor];

self.label.text=error.debugDescription;

}];

}

+(BOOL)extractIdentity:(SecIdentityRef*)outIdentity andTrust:(SecTrustRef*)outTrust fromPKCS12Data:(NSData*)inPKCS12Data {

OSStatussecurityError =errSecSuccess;

//client certificate password

NSDictionary*optionsDictionary = [NSDictionarydictionaryWithObject:@"123456"

forKey:(__bridgeid)kSecImportExportPassphrase];

CFArrayRefitems =CFArrayCreate(NULL,0,0,NULL);

securityError =SecPKCS12Import((__bridgeCFDataRef)inPKCS12Data,(__bridgeCFDictionaryRef)optionsDictionary,&items);

if(securityError ==0) {

CFDictionaryRefmyIdentityAndTrust =CFArrayGetValueAtIndex(items,0);

constvoid*tempIdentity =NULL;

tempIdentity=CFDictionaryGetValue(myIdentityAndTrust,kSecImportItemIdentity);

*outIdentity = (SecIdentityRef)tempIdentity;

constvoid*tempTrust =NULL;

tempTrust =CFDictionaryGetValue(myIdentityAndTrust,kSecImportItemTrust);

*outTrust = (SecTrustRef)tempTrust;

}else{

NSLog(@"Failedwith error code %d",(int)securityError);

returnNO;

}

returnYES;

}

/**

一.非瀏覽器應(yīng)用(iOS app)與服務(wù)器AFNetworking HTTPS ssl認證

雖然是HTTPS的網(wǎng)站,但是服務(wù)器端也要設(shè)置對客戶端提供認證證書忽略(此處與瀏覽器與服務(wù)器SSl雙向認證不太一樣).

AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey];

//是否允許,NO--不允許無效的證書,設(shè)置允許(YES)(因為我們的證書一般都是自簽名的,并不是像谷歌那種大型網(wǎng)站權(quán)威頒布的官方認證證書)

securityPolicy.allowInvalidCertificates=YES;

//validatesDomainName是否需要驗證域名倡缠,默認為YES;

//假如證書的域名與你請求的域名不一致茎活,需把該項設(shè)置為NO昙沦;如設(shè)成NO的話,即服務(wù)器使用其他可信任機構(gòu)頒發(fā)的證書载荔,也可以建立連接盾饮,這個非常危險,建議打開。

//置為NO丘损,主要用于這種情況:客戶端請求的是子域名普办,而證書上的是另外一個域名。因為SSL證書上的域名是獨立的徘钥,假如證書上注冊的域名是www.google.com衔蹲,那么mail.google.com是無法驗證通過的;當(dāng)然呈础,有錢可以注冊通配符的域名*.google.com舆驶,但這個還是比較貴的。

//如置為NO而钞,建議自己添加對應(yīng)域名的校驗邏輯沙廉。

//securityPolicy.validatesDomainName=NO;

manager.securityPolicy = securityPolicy;

這幾句代碼是必需的,訪問HTTPS(比http多加這些).

AFSSLPinningModeNone,AFSSLPinningModePublicKey,AFSSLPinningModeCertificate,這三個屬性是上邊紅色位置的三種情況.

SSL Pinning可以理解為證書綁定,是指客戶端直接保存服務(wù)端的證書笨忌,建立https連接時直接對比服務(wù)端返回的和客戶端保存的兩個證書是否一樣蓝仲,一樣就表明證書是真的,不再去系統(tǒng)的信任證書機構(gòu)里尋找驗證官疲。這適用于非瀏覽器應(yīng)用袱结,因為瀏覽器跟很多未知服務(wù)端打交道,無法把每個服務(wù)端的證書都保存到本地途凫,但CS架構(gòu)的像手機APP事先已經(jīng)知道要進行通信的服務(wù)端垢夹,可以直接在客戶端保存這個服務(wù)端的證書用于校驗。

為什么直接對比就能保證證書沒問題维费?如果中間人從客戶端取出證書果元,再偽裝成服務(wù)端跟其他客戶端通信,它發(fā)送給客戶端的這個證書不就能通過驗證嗎犀盟?確實可以通過驗證而晒,但后續(xù)的流程走不下去,因為下一步客戶端會用證書里的公鑰加密阅畴,中間人沒有這個證書的私鑰就解不出內(nèi)容倡怎,也就截獲不到數(shù)據(jù),這個證書的私鑰只有真正的服務(wù)端有贱枣,中間人偽造證書主要偽造的是公鑰监署。

為什么要用SSLPinning?正常的驗證方式不夠嗎纽哥?如果服務(wù)端的證書是從受信任的的CA機構(gòu)頒發(fā)的钠乏,驗證是沒問題的,但CA機構(gòu)頒發(fā)證書比較昂貴春塌,小企業(yè)或個人用戶可能會選擇自己頒發(fā)證書晓避,這樣就無法通過系統(tǒng)受信任的CA機構(gòu)列表驗證這個證書的真?zhèn)瘟舜睾矗孕枰猄SL Pinning這樣的方式去驗證。

在iOS開發(fā)中,從Xcode7和iOS9開始,Apple提升了App的網(wǎng)絡(luò)安全性,App默認只能進行對采用權(quán)威機構(gòu)簽名頒發(fā)證書的Web站點進行訪問(信任的HTTPS),而自簽名的證書的HTTPS站點也被列為屬于例外,所以我們需要在App的Info.plist中單獨為我們的域名設(shè)置Exception Domains"白名單”.也可以使用放開全部的設(shè)置NSAllowsArbitraryLoads為true.

1.AFSSLPinningModeNone

這個模式表示不做SSL pinning够滑,只跟瀏覽器一樣在系統(tǒng)的信任機構(gòu)列表里驗證服務(wù)端返回的證書垦写。若證書是信任機構(gòu)簽發(fā)的就會通過,若是自己服務(wù)器生成的證書彰触,這里是不會通過的梯投。

所以要用到上面securityPolicy.allowInvalidCertificates=YES;

必須修改infoplist文件即:像http請求一樣(App TransportSecurity Settings——>Allow Arbitrary LoadsYES.)

這個屬性使數(shù)據(jù)不安全,一些中間人(抓包工具)會截取到數(shù)據(jù)接口.

2.AFSSLPinningModeCertificate:

這個模式表示用證書綁定方式驗證證書,需要客戶端保存有服務(wù)端的證書拷貝况毅,這里驗證分兩步分蓖,第一步驗證證書的域名/有效期等信息,第二步是對比服務(wù)端返回的證書跟客戶端返回的是否一致尔许。

驗證服務(wù)器身份在沒有使用代理的時候可以正常訪問服務(wù)器的資源,但是一旦用戶給手機網(wǎng)絡(luò)設(shè)置使用了如Charle那樣的HTTPS/SSL代理服務(wù),則會出現(xiàn)服務(wù)器證書驗證失敗,SSL網(wǎng)絡(luò)連接會斷開,老板再也不用擔(dān)心數(shù)據(jù)接口被人抓包或者代理給扒出來了.故達到防止中間人攻擊的效果.

無需修改infoplist(自己測試了).

這個證書是服務(wù)器端的證書(.cer文件)(可以是根證書,也可以是證書,總之必須是服務(wù)器的),把這個證書直接copy到Xcode工程,程序會自動讀取.cer文件.

3.AFSSLPinningModePublicKey (和第二個差不多)

這個模式同樣是用證書綁定方式驗證么鹤,客戶端要有服務(wù)端的證書拷貝,只是驗證時只驗證證書里的公鑰味廊,不驗證證書的有效期等信息蒸甜。只要公鑰是正確的,就能保證通信不會被竊聽余佛,因為中間人沒有私鑰柠新,無法解開通過公鑰加密的數(shù)據(jù)。

二.客戶端瀏覽器與服務(wù)器端HTTPS雙向認證

①瀏覽器發(fā)送一個連接請求給安全服務(wù)器辉巡。

②服務(wù)器將自己的證書恨憎,以及同證書相關(guān)的信息發(fā)送給客戶瀏覽器。

③客戶瀏覽器檢查服務(wù)器送過來的證書是否是由自己信賴的CA中心所簽發(fā)的郊楣。如果是憔恳,就繼續(xù)執(zhí)行協(xié)議;如果不是净蚤,客戶瀏覽器就給客戶一個警告消息:警告客戶這個證書不是可以信賴的钥组,詢問客戶是否需要繼續(xù)。

④接著客戶瀏覽器比較證書里的消息今瀑,例如域名和公鑰者铜,與服務(wù)器剛剛發(fā)送的相關(guān)消息是否一致,如果是一致的放椰,客戶瀏覽器認可這個服務(wù)器的合法身份。

⑤服務(wù)器要求客戶發(fā)送客戶自己的證書愉粤。收到后砾医,服務(wù)器驗證客戶的證書,如果沒有通過驗證衣厘,拒絕連接如蚜;如果通過驗證压恒,服務(wù)器獲得用戶的公鑰。

⑥客戶瀏覽器告訴服務(wù)器自己所能夠支持的通訊對稱密碼方案错邦。

⑦服務(wù)器從客戶發(fā)送過來的密碼方案中探赫,選擇一種加密程度最高的密碼方案,用客戶的公鑰加過密后通知瀏覽器撬呢。

⑧瀏覽器針對這個密碼方案伦吠,選擇一個通話密鑰,接著用服務(wù)器的公鑰加過密后發(fā)送給服務(wù)器魂拦。

⑨服務(wù)器接收到瀏覽器送過來的消息毛仪,用自己的私鑰解密,獲得通話密鑰芯勘。

⑩服務(wù)器箱靴、瀏覽器接下來的通訊都是用對稱密碼方案,對稱密鑰是加過密的荷愕。

這兩種形式雖然同樣是ssl認證,本人感覺并不是一個意思.開始的時候是按照瀏覽器與服務(wù)器端的ssl雙向認證來做AFNetworking,服務(wù)器端設(shè)置必須客戶端提供證書才能訪問網(wǎng)站,否則403,但是試了好多次都是請求失敗(萬念俱灰).查看別人的HTTPS接口例子不一樣和之前做的.于是認為這兩種驗證方式是不同的.把服務(wù)器端必需的客戶端證書,改成忽略,經(jīng)過測試,用AFNetworking使用服務(wù)器端證書,也能達到加密的作用,而且AFNetworking,確實是這么應(yīng)用的.代碼很少,但是這里面是非瀏覽器應(yīng)用如何應(yīng)用,以及和瀏覽器的雙向認證區(qū)分開.

我是從下面這些個說法中總結(jié)的:

//瀏覽器與服務(wù)端雙向認證

http://www.reibang.com/p/8b4312c34808

http://www.reibang.com/p/20d5fb4cd76d

//https為什么還要改infoplist如何防止抓包(中間人)

http://www.reibang.com/p/c6a903da8346

非瀏覽器應(yīng)用AFNetworking SSLPINNing (雙向認證)

http://www.cocoachina.com/ios/20140916/9632.html

HTTPS接口例子:

https://tv.diveinedu.com/channel/

https://daka.facenano.com/checkin/v1/app_binding?phone_number=18700000001&app_version_code=2&device=mobile_ios&company_tag=iPhone-demo&phone_imei=6D56F277-0AAA-4F32-AD01-6C55AEE75964&verification_code=3216

*/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末衡怀,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子安疗,更是在濱河造成了極大的恐慌抛杨,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茂契,死亡現(xiàn)場離奇詭異蝶桶,居然都是意外死亡,警方通過查閱死者的電腦和手機掉冶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門真竖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人厌小,你說我怎么就攤上這事恢共。” “怎么了璧亚?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵讨韭,是天一觀的道長。 經(jīng)常有香客問我癣蟋,道長透硝,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任疯搅,我火速辦了婚禮濒生,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘幔欧。我一直安慰自己罪治,他們只是感情好丽声,可當(dāng)我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著觉义,像睡著了一般雁社。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上晒骇,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天霉撵,我揣著相機與錄音,去河邊找鬼厉碟。 笑死喊巍,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的箍鼓。 我是一名探鬼主播崭参,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼款咖!你這毒婦竟也來了何暮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤铐殃,失蹤者是張志新(化名)和其女友劉穎海洼,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體富腊,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡坏逢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了赘被。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片是整。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖民假,靈堂內(nèi)的尸體忽然破棺而出浮入,到底是詐尸還是另有隱情,我是刑警寧澤羊异,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布事秀,位于F島的核電站,受9級特大地震影響野舶,放射性物質(zhì)發(fā)生泄漏易迹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一平道、第九天 我趴在偏房一處隱蔽的房頂上張望赴蝇。 院中可真熱鬧,春花似錦巢掺、人聲如沸句伶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽考余。三九已至,卻和暖如春轧苫,著一層夾襖步出監(jiān)牢的瞬間楚堤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工含懊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留身冬,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓岔乔,卻偏偏與公主長得像酥筝,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子雏门,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,877評論 2 345