iOS開發(fā)app實現(xiàn)支持HTTPS

什么是HTTPS床佳?

在說HTTPS之前先說說什么是HTTP蔓彩,HTTP就是我們平時瀏覽網(wǎng)頁時候使用的一種協(xié)議导俘。HTTP協(xié)議傳輸?shù)臄?shù)據(jù)都是未加密的峦耘,也就是明文的,因此使用HTTP協(xié)議傳輸隱私信息非常不安全旅薄。為了保證這些隱私數(shù)據(jù)能加密傳輸辅髓,于是網(wǎng)景公司設(shè)計了SSL(Secure Sockets Layer)協(xié)議用于對HTTP協(xié)議傳輸?shù)臄?shù)據(jù)進(jìn)行加密,從而就誕生了HTTPS赋秀。

如果從最終的數(shù)據(jù)解析角度去看HTTPS利朵,HTTPS與HTTP沒有任何區(qū)別律想,HTTPS就是將HTTP協(xié)議數(shù)據(jù)包放到SSL/TSL層加密后猎莲,在TCP/IP層組成IP數(shù)據(jù)報去傳輸,以此保證傳輸數(shù)據(jù)的安全技即;在接受端著洼,SSL/TSL將接收的數(shù)據(jù)包解密之后,將數(shù)據(jù)傳給HTTP協(xié)議層而叼,獲得普通的HTTP數(shù)據(jù),簡單地概括為 HTTPS = HTTP + SSL/TLS + TCP身笤。

在WWDC 2016開發(fā)者大會上,蘋果宣布在2016年底前所有iOS應(yīng)用都必須啟用App Transport Security安全功能葵陵,對于未啟用App Transport Security安全功能的app蘋果都會進(jìn)行更嚴(yán)格的審核液荸,如果沒有充分的理由,很可能你的app會被拒絕上架脱篙。

此處引用蘋果官方文檔內(nèi)容:

App Store Review for ATS
此處省略一大段蘋果官方文檔內(nèi)容.....
When submitting your app to the App Store, provide sufficient information for the App Store to determine why your app cannot make secure connections by default.

一:公司使用的是知名CA頒發(fā)的證書,服務(wù)器配置符合蘋果ATS要求:

App Transport Security 要求 TLS 1.2族操,而且它要求站點使用支持forward secrecy協(xié)議的密碼队寇。證書也要求是符合ATS規(guī)格的,ATS只信任知名CA頒發(fā)的證書,小公司所使用的 self signed certificate冒掌,還是會被ATS攔截。因此慎重檢查與你的應(yīng)用交互的服務(wù)器是不是符合ATS的要求非常重要丹莲。

官方文檔App Transport Security Technote對CA頒發(fā)的證書要求:

The leaf server certificate must be signed with one of the following types of keys:
1.Rivest-Shamir-Adleman (RSA) key with a length of at least 2048 bits
2.Elliptic-Curve Cryptography (ECC) key with a size of at least 256 bits
In addition, the leaf server certificate hashing algorithm must be Secure Hash Algorithm 2 (SHA-2) with a digest length, sometimes called a “fingerprint,” of at least 256 (that is, SHA-256 or greater).

這種情況不需要在Bundle中引入CA文件昼汗,可以交給系統(tǒng)去判斷服務(wù)器端的證書是不是SSL證書,驗證過程也不需要我們?nèi)ゾ唧w實現(xiàn)取视。

二:基于AFNetWorking的SSL特定服務(wù)器證書信任處理硝皂,重寫AFNetWorking的customSecurityPolicy方法,這里我創(chuàng)建了一個HttpRequest工具類,分別對GET和POST方法進(jìn)行了封裝作谭,以GET方法為例:
+ (void)getWithUrl:(NSString *)url
            params:(NSDictionary *)params
           success:(void (^)(id))success
              fail:(void (^)(NSError *))fail
{
 //初始化AFHTTPSessionManager 
    AFHTTPSessionManager *manager = [self manager];

// 發(fā)出GET請求
    [manager GET:url parameters:params success:^(AFHTTPRequestOperation *operation, id response){
        if (success) {
            success(response);
        }
    } fail:^(AFHTTPRequestOperation *operation, NSError *error) {
        if (error) {
            fail(error);
        }
    }];
}

+ (AFHTTPSessionManager *)manager {
  //初始化AFHTTPSessionManager 
   AFHTTPSessionManager  *manager = [AFHTTPSessionManager manager];
   switch (sg_requestType) {
        case kZHRequestTypeJSON: {
            manager.requestSerializer = [AFJSONRequestSerializer serializer];
            break;
        }
        case kZHRequestTypePlainText: {
            manager.requestSerializer = [AFHTTPRequestSerializer serializer];
            break;
        }
    }
    // https ssl 驗證  KOpenHttpsSSL為證書名稱的宏
    if (KOpenHttpsSSL) {
        [manager setSecurityPolicy:[self customSecurityPolicy]];
    }
    return manager;
}
+ (AFSecurityPolicy*)customSecurityPolicy {
    // /先導(dǎo)入證書
    NSString *cerFilePath = [[NSBundle mainBundle] pathForResource:KCertificateName ofType:@"cer"];//證書的路徑
    NSData *certFileData = [NSData dataWithContentsOfFile:cerFilePath];
    
    // AFSSLPinningModeCertificate 證書驗證模式
    AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
    
    // allowInvalidCertificates 是否允許 self signed certificate
    // 驗證 self signed certificate要設(shè)置為YES
    securityPolicy.allowInvalidCertificates = YES;
    //是否需要驗證域名
    securityPolicy.validatesDomainName = NO;
    
    securityPolicy.pinnedCertificates = [NSSet setWithArray:@[certFileData]];
    
    return securityPolicy;
}

這樣吧彪,就能夠在AFNetWorking的基礎(chǔ)上使用HTTPS協(xié)議訪問特定服務(wù)器,但是不能信任根證書的CA文件丢早,因此這種方式存在風(fēng)險姨裸,讀取pinnedCertificates中的證書數(shù)組的時候有可能失敗秧倾,如果證書不符合,certFileData就會為nil傀缩。

三:更改系統(tǒng)方法那先,發(fā)送異步NSURLConnection請求。
//發(fā)送https網(wǎng)絡(luò)請求
- (void)sendHttpsRequest
{
    NSString *urlStr = @"https://api.weibo.com/";
    NSURL *url = [NSURL URLWithString:urlStr];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];
    NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
    [connection start];
}

重點在于處理NSURLConnection的didReceiveAuthenticationChallenge代理方法赡艰,對CA文件進(jìn)行驗證售淡,并建立信任連接。

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
    
    return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    
    /*
     //直接驗證服務(wù)器是否被認(rèn)證(serverTrust)慷垮,這種方式直接忽略證書驗證揖闸,直接建立連接,但不能過濾其它URL連接料身,可以理解為一種折衷的處理方式汤纸,實際上并不安全,因此不推薦芹血。
     SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
     return [[challenge sender] useCredential: [NSURLCredential credentialForTrust: serverTrust]
     forAuthenticationChallenge: challenge];
     */
    if ([[[challenge protectionSpace] authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust]) {
        do
        {
            SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
            NSCAssert(serverTrust != nil, @"serverTrust is nil");
            if(nil == serverTrust)
                break; /* failed */
            /**
             *  導(dǎo)入多張CA證書(Certification Authority贮泞,支持SSL證書以及自簽名的CA)
             */
            NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"cloudwin" ofType:@"cer"];//自簽名證書
            NSData* caCert = [NSData dataWithContentsOfFile:cerPath];
            
            NSString *cerPath2 = [[NSBundle mainBundle] pathForResource:@"apple" ofType:@"cer"];//SSL證書
            NSData * caCert2 = [NSData dataWithContentsOfFile:cerPath2];
            
            NSCAssert(caCert != nil, @"caCert is nil");
            if(nil == caCert)
                break; /* failed */
            
            NSCAssert(caCert2 != nil, @"caCert2 is nil");
            if (nil == caCert2) {
                break;
            }
            
            SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caCert);
            NSCAssert(caRef != nil, @"caRef is nil");
            if(nil == caRef)
                break; /* failed */
            
            SecCertificateRef caRef2 = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caCert2);
            NSCAssert(caRef2 != nil, @"caRef2 is nil");
            if(nil == caRef2)
                break; /* failed */
            
            NSArray *caArray = @[(__bridge id)(caRef),(__bridge id)(caRef2)];
            
            NSCAssert(caArray != nil, @"caArray is nil");
            if(nil == caArray)
                break; /* failed */
            
            OSStatus status = SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)caArray);
            NSCAssert(errSecSuccess == status, @"SecTrustSetAnchorCertificates failed");
            if(!(errSecSuccess == status))
                break; /* failed */
            
            SecTrustResultType result = -1;
            status = SecTrustEvaluate(serverTrust, &result);
            if(!(errSecSuccess == status))
                break; /* failed */
            NSLog(@"stutas:%d",(int)status);
            NSLog(@"Result: %d", result);
            
            BOOL allowConnect = (result == kSecTrustResultUnspecified) || (result == kSecTrustResultProceed);
            if (allowConnect) {
                NSLog(@"success");
            }else {
                NSLog(@"error");
            }
            /* https://developer.apple.com/library/ios/technotes/tn2232/_index.html */
            /* https://developer.apple.com/library/mac/qa/qa1360/_index.html */
            /* kSecTrustResultUnspecified and kSecTrustResultProceed are success */
            if(! allowConnect)
            {
                break; /* failed */
            }
            
#if 0
            /* Treat kSecTrustResultConfirm and kSecTrustResultRecoverableTrustFailure as success */
            /*   since the user will likely tap-through to see the dancing bunnies */
            if(result == kSecTrustResultDeny || result == kSecTrustResultFatalTrustFailure || result == kSecTrustResultOtherError)
                break; /* failed to trust cert (good in this case) */
#endif
            
            // The only good exit point
            return [[challenge sender] useCredential: [NSURLCredential credentialForTrust: serverTrust]
                          forAuthenticationChallenge: challenge];
            
        } while(0);
    }
    
    return [[challenge sender] cancelAuthenticationChallenge: challenge];
    
}

這里的關(guān)鍵在于result參數(shù)的值,根據(jù)官方文檔的說明幔烛,判斷(result == kSecTrustResultUnspecified) || (result == kSecTrustResultProceed)的值啃擦,若為1,則該網(wǎng)站的CA被app信任成功饿悬,可以建立數(shù)據(jù)連接令蛉,這意味著所有由該CA簽發(fā)的各個服務(wù)器證書都被信任,而訪問其它沒有被信任的任何網(wǎng)站都會連接失敗狡恬。該CA文件既可以是SLL也可以是自簽名珠叔。

NSURLConnection的其它代理方法實現(xiàn)

#pragma mark -- connect的異步代理方法
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    NSLog(@"請求被響應(yīng)");
    _mData = [[NSMutableData alloc]init];
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(nonnull NSData *)data {
    NSLog(@"開始返回數(shù)據(jù)片段");
    
    [_mData appendData:data];
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
    NSLog(@"鏈接完成");
    //可以在此解析數(shù)據(jù)
    NSString *receiveInfo = [NSJSONSerialization JSONObjectWithData:self.mData options:NSJSONReadingAllowFragments error:nil];
    NSLog(@"received data:\\\\n%@",self.mData);
    NSLog(@"received info:\\\\n%@",receiveInfo);
}

//鏈接出錯
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    NSLog(@"error - %@",error);
}

至此,HTTPS信任證書的問題得以解決傲宜。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末运杭,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子函卒,更是在濱河造成了極大的恐慌辆憔,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件报嵌,死亡現(xiàn)場離奇詭異虱咧,居然都是意外死亡,警方通過查閱死者的電腦和手機锚国,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門腕巡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人血筑,你說我怎么就攤上這事绘沉〖彘梗” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵车伞,是天一觀的道長择懂。 經(jīng)常有香客問我,道長另玖,這世上最難降的妖魔是什么困曙? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮谦去,結(jié)果婚禮上慷丽,老公的妹妹穿的比我還像新娘。我一直安慰自己鳄哭,他們只是感情好要糊,可當(dāng)我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著窃诉,像睡著了一般杨耙。 火紅的嫁衣襯著肌膚如雪赤套。 梳的紋絲不亂的頭發(fā)上飘痛,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音容握,去河邊找鬼宣脉。 笑死,一個胖子當(dāng)著我的面吹牛剔氏,可吹牛的內(nèi)容都是我干的塑猖。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼谈跛,長吁一口氣:“原來是場噩夢啊……” “哼羊苟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起感憾,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤蜡励,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后阻桅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凉倚,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年嫂沉,在試婚紗的時候發(fā)現(xiàn)自己被綠了稽寒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡趟章,死狀恐怖杏糙,靈堂內(nèi)的尸體忽然破棺而出慎王,到底是詐尸還是另有隱情,我是刑警寧澤宏侍,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布柬祠,位于F島的核電站,受9級特大地震影響负芋,放射性物質(zhì)發(fā)生泄漏漫蛔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一旧蛾、第九天 我趴在偏房一處隱蔽的房頂上張望莽龟。 院中可真熱鬧,春花似錦锨天、人聲如沸毯盈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽搂赋。三九已至,卻和暖如春益缠,著一層夾襖步出監(jiān)牢的瞬間脑奠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工幅慌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宋欺,地道東北人。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓胰伍,卻偏偏與公主長得像齿诞,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子骂租,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容

  • 原文地址 http://blog.csdn.net/u012409247/article/details/4985...
    0fbf551ff6fb閱讀 3,514評論 0 13
  • 一祷杈、作用 不使用SSL/TLS的HTTP通信,就是不加密的通信渗饮。所有信息明文傳播但汞,帶來了三大風(fēng)險。 (1)竊聽風(fēng)險...
    XLsn0w閱讀 10,486評論 2 44
  • 一. HTTPS 其實HTTPS從最終的數(shù)據(jù)解析的角度抽米,與HTTP沒有任何的區(qū)別特占,HTTPS就是將HTTP協(xié)議數(shù)據(jù)...
    獨酌丿紅顏閱讀 3,646評論 4 122
  • 天空灰白 像吸滿水的棉 行人緊張的看著天 腳步匆匆 擔(dān)心不知道哪一秒大雨點就會被風(fēng)吹下來 終于到了目的地 放松的看...
    貓二蛋閱讀 175評論 0 0
  • 世事怎能念曾經(jīng) 今天一早看到這樣一句話:命運嘛标捺,休論公道懊纳! 短短七個字揉抵,平靜之中有著點無奈、清醒嗤疯、看透冤今,但在這通透...
    狗西西閱讀 868評論 0 0