How to make your iOS apps more secure with SSL pinning

Posted in :

swift 和 obj-c 完成 ssl 的寫法如下:


We can start by instantiating an NSURLSession object with the default session configuration.

Swift
self.urlSession = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: self, delegateQueue: nil)
Objective C
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
self.urlSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];

use the dataTaskWithURL:completionHandler: method for the SSL pinning test. The request we send will look something like this:

Swift
self.urlSession?.dataTaskWithURL(NSURL(string:self.urlTextField.text!)!, completionHandler: { (NSData data, NSURLResponse response, NSError error) Void in
    // response management code
}).resume()
Objective C
[[self.urlSession dataTaskWithURL:[NSURL URLWithString:self.textField.text] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        // response management code
    }] resume];

implemented within the URLSession:didReceiveChallenge:completionHandler:delegatemethod. Note that, upon the creation of the NSURLSession object, we assigned self as the delegate so that this method is called on our object.

Swift
func URLSession(session: NSURLSession,  didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
    let serverTrust = challenge.protectionSpace.serverTrust
    let certificate = SecTrustGetCertificateAtIndex(serverTrust!, 0)

    // Set SSL policies for domain name check
    let policies = NSMutableArray();
    policies.addObject(SecPolicyCreateSSL(true, (challenge.protectionSpace.host)))
    SecTrustSetPolicies(serverTrust!, policies);

    // Evaluate server certificate
    var result: SecTrustResultType = 0
    SecTrustEvaluate(serverTrust!, &result)
    let isServerTrusted:Bool = (Int(result) == kSecTrustResultUnspecified || Int(result) == kSecTrustResultProceed)

    // Get local and remote cert data
    let remoteCertificateData:NSData = SecCertificateCopyData(certificate!)
    let pathToCert = NSBundle.mainBundle().pathForResource(githubCert, ofType: "cer")
    let localCertificate:NSData = NSData(contentsOfFile: pathToCert!)!

    if (isServerTrusted && remoteCertificateData.isEqualToData(localCertificate)) {
        let credential:NSURLCredential = NSURLCredential(forTrust: serverTrust!)
        completionHandler(.UseCredential, credential)
    } else {
        completionHandler(.CancelAuthenticationChallenge, nil)
    }
}

Objective C
-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {

    // Get remote certificate
    SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
    SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, 0);

    // Set SSL policies for domain name check
    NSMutableArray *policies = [NSMutableArray array];
    [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)challenge.protectionSpace.host)];
    SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);

    // Evaluate server certificate
    SecTrustResultType result;
    SecTrustEvaluate(serverTrust, &result);
    BOOL certificateIsValid = (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);

    // Get local and remote cert data
    NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate));
    NSString *pathToCert = [[NSBundle mainBundle]pathForResource:@"github.com" ofType:@"cer"];
    NSData *localCertificate = [NSData dataWithContentsOfFile:pathToCert];

    // The pinnning check
    if ([remoteCertificateData isEqualToData:localCertificate] && certificateIsValid) {
        NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
        completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
    } else {
        completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, NULL);
    }
}

如果不使用 local certificate:

    // Get remote certificate

    SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;

    

    // Set SSL policies for domain name check

    NSMutableArray *policies = [NSMutableArray array];

    [policies addObject🙁__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)challenge.protectionSpace.host)];

    SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);

    

    // Evaluate server certificate

    SecTrustResultType result;

    SecTrustEvaluate(serverTrust, &result);

    BOOL certificateIsValid = (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);

    

    // The pinnning check

    if (certificateIsValid) {

        NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];

        completionHandler(NSURLSessionAuthChallengeUseCredential, credential);

    } else {

        completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, NULL);

    }

 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *