iOS Https協議 正規證書 自簽證書訪問數據

使用正規CA證書

正規證書:是由一些數字證書認證機構頒發的證書。
優點:不需要進行任何配置,記得將url前面加上https即可正常訪問,達到加密以及通過審核的目的。
缺點:要錢,而且費用還不低。當然也有提供免費的正規證書的,比如騰訊云和阿里云,但都是有時效的。

使用自簽證書

證書由后臺提供,證書的生成方法 .

  • 1.首先web服務器必須提供一個ssl證書,需要一個 .crt 文件, 在開始寫代碼前,先要把 .crt 文件轉成 .cer 文件,然后在加到Bundle 里面. 使用openssl 進行轉換: openssl x509 -in 你的證書.crt -out 你的證書.cer -outform der

  • 2.通過安裝crt文件,電腦導出.

    • 先打開“鑰匙串訪問”

    • 選中你安裝的crt文件證書,選擇“文件”--》“導出項目”


    • 選擇.cer證書,存儲即可。


使用第三方庫AFNetworking,配置證書。

寫工具類#import "AFNetworking.h"

  • import "AFNetworking.h"

#import <Foundation/Foundation.h>

@interface HttpRequest : NSObject
/**
 *  發送一個POST請求
 *
 *  @param url     請求路徑
 *  @param params  請求參數
 *  @param success 請求成功后的回調(請將請求成功后想做的事情寫到這個block中)
 *  @param failure 請求失敗后的回調(請將請求失敗后想做的事情寫到這個block中)
 */
+ (void)post:(NSString *)url params:(NSDictionary *)params success:(void (^)(id responseObj))success failure:(void (^)(NSError *error))failure;

@end
  • import "AFNetworking.m"

#import "HttpRequest.h"
#import "AFNetworking.h"

/**
 *  是否開啟https SSL 驗證
 *
 *  @return YES為開啟,NO為關閉
 */
#define openHttpsSSL YES
/**
 *  SSL 證書名稱,僅支持cer格式。“app.bishe.com.cer”,則填“app.bishe.com”
 */
#define certificate @"adn"

@implementation HttpRequest

+ (void)post:(NSString *)url params:(NSDictionary *)params success:(void (^)(id))success failure:(void (^)(NSError *))failure
{
      //對應域名的校驗我認為應該在url中去邏輯判斷。--》馮龍騰寫
      //通過對url字符串的切割對子域名進行邏輯驗證處理。
    
    // 1.獲得請求管理者
    AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
    // 2.申明返回的結果是text/html類型
    mgr.responseSerializer = [AFHTTPResponseSerializer serializer];
    mgr.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/json",@"text/javascript",@"text/html",nil];
    // 3.設置超時時間為10s
    mgr.requestSerializer.timeoutInterval = 10;
    
    // 加上這行代碼,https ssl 驗證。
    if(openHttpsSSL)
    {
        [mgr setSecurityPolicy:[self customSecurityPolicy]];
    }
    
    // 4.發送POST請求
    [mgr POST:url parameters:params
      success:^(AFHTTPRequestOperation *operation, id responseObj) {
          if (success) {
              success(responseObj);
          }
      } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
          if (failure) {
              failure(error);
          }
      }];
}

+ (AFSecurityPolicy*)customSecurityPolicy
{
    // /先導入證書
    NSString *cerPath = [[NSBundle mainBundle] pathForResource:certificate ofType:@"cer"];//證書的路徑
    NSData *certData = [NSData dataWithContentsOfFile:cerPath];
    
  //  AFSSLPinningModeNone:完全信任服務器證書;
    //AFSSLPinningModePublicKey:只比對服務器證書和本地證書的Public Key是否一致,如果一致則信任服 務器證書;
   // AFSSLPinningModeCertificate:比對服務器證書和本地證書的所有內容,完全一致則信任服務器證書;

 //  選擇那種模式呢?

//  AFSSLPinningModeCertificate:最安全的比對模式。但是也比較麻煩,因為證書是打包在APP中,如果服 
 務器證書改變或者到期,舊版本無法使用了,我們就需要用戶更新APP來使用最新的證書。
//  AFSSLPinningModePublicKey:只比對證書的Public Key,只要Public Key沒有改變,證書的其他變動都不會影響使用。 如果你不能保證你的用戶總是使用你的APP的最新版本,所以我們使用AFSSLPinningModePublicKey。

   AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
    
     // allowInvalidCertificates 是否允許無效證書(不在證書信任鏈內所以是NO,也就是自建的證書),默認為NO
    // 如果是需要驗證自建證書,需要設置為YES
    securityPolicy.allowInvalidCertificates = YES;
    
    //validatesDomainName 是否需要驗證域名,默認為YES;
    //假如證書的域名與你請求的域名不一致,需把該項設置為NO;如設成NO的話,即服務器使用其他可信任機構頒發的證書,也可以建立連接,這個非常危險,建議打開。
    //置為NO,主要用于這種情況:客戶端請求的是子域名,而證書上的是另外一個域名。因為SSL證書上的域名是獨立的,假如證書上注冊的域名是www.google.com,那么mail.google.com是無法驗證通過的;當然,有錢可以注冊通配符的域名*.google.com,但這個還是比較貴的。
    //如置為NO,建議自己添加對應域名的校驗邏輯。
    securityPolicy.validatesDomainName = NO;
    if (certData) {
        securityPolicy.pinnedCertificates = @[certData];
    }
    
    
    return securityPolicy;
}
@end

AFSSLPinningModeCertificate采用該模式證書有過期時間,自簽證書要自己更新證書特別要注意。

以上示例的Demo

補充

我前面說過,驗證站點證書,是通過域名的,如果服務器端站點沒有綁定域名(萬惡的備案),僅靠IP地址上面的方法是絕對不行的。怎么辦?答案是想通過設置是不可以的,你只能修改AFNetworking2的源代碼!打開AFSecurityPolicy.m文件,找到方法:

- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
                  forDomain:(NSString *)domain
將下面這部分注釋掉

//            SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
//
//            if (!AFServerTrustIsValid(serverTrust)) {
//                return NO;
//            }
//
//            if (!self.validatesCertificateChain) {
//                return YES;
//            }

這樣,AFSecurityPolicy就只會比對服務器證書和內嵌證書是否一致,不會再驗證證書是否和站點域名一致了。

這么做為什么是安全的?了解HTTPS的人都知道,整個驗證體系中,最核心的實際上是服務器的私鑰。私鑰永遠,永遠也不會離開服務器,或者以任何形式向外傳輸。私鑰和公鑰是配對的,如果事先在客戶端預留了公鑰,只要服務器端的公鑰和預留的公鑰一致,實際上就已經可以排除中間人攻擊了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容