简体   繁体   中英

SSL Pinning using AFNetworking in iOS not working

I am using AFnetworking. My application webserver is in TLS 1.2. I want to add Certificate pinning to my iOS app. My code as below:

       AFHTTPSessionManager *manager=[[AFHTTPSessionManager manager] initWithBaseURL:serviceURL];

    NSSet *certificates = [AFSecurityPolicy certificatesInBundle:[NSBundle mainBundle]];
    AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:certificates];
    policy.validatesDomainName = YES;
    policy.allowInvalidCertificates = YES;
    opManager.securityPolicy = policy;

I have my valid server certificate in my bundle and with this code webservices are working fine. But when I tried the same with an incorrect sample certificate, that time also webservices are working. I even tried with no certificates in bundle, that time also, webservices are working fine. Could anyone please explain this? AppTransportSecurity is turned ON in my app.

    <key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <false/>
</dict>

I found a solution to this issue. Please find below the code I used to replace existing code. It's working as expected.

        AFHTTPSessionManager *opManager=[[AFHTTPSessionManager manager] initWithBaseURL:baseUrl];
    opManager.requestSerializer = [AFHTTPRequestSerializer serializer];
    opManager.responseSerializer = [AFHTTPResponseSerializer serializer];

    // SSL Pinning
    NSString *certificatePath = [[NSBundle mainBundle] pathForResource:@"xxxxxxxx.com" ofType:@"der"];
    NSData *certificateData = [NSData dataWithContentsOfFile:certificatePath];

    AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
    [securityPolicy setAllowInvalidCertificates:YES];
    [securityPolicy setPinnedCertificates:@[certificateData]];
    [opManager setSecurityPolicy:securityPolicy];

The following function will do the public key certificate pinning for you:

- (AFHTTPSessionManager*) getSessionManager: (NSString *) serverUrl {
    AFHTTPSessionManager * sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString: serverUrl]];
    if ([serverUrl hasPrefix:@"https"]) {
        NSString *certificate = nil;
        NSString *cerPath = [[NSBundle mainBundle] pathForResource: certificate ofType:@"der"];
        if (cerPath != nil) {
            NSData *certData = [NSData dataWithContentsOfFile: cerPath];
            AFSecurityPolicy* policy = [AFSecurityPolicy policyWithPinningMode: AFSSLPinningModePublicKey];
            policy.pinnedCertificates = [NSSet setWithArray: @[certData]];
            [policy setValidatesDomainName: YES];
            [policy setAllowInvalidCertificates: NO];
            sessionManager.securityPolicy = policy;
        }
    }
    return sessionManager;
}

And to call this function use:

AFHTTPSessionManager * sessionManager = [self getSessionManager: @"https://example.com"];

Obtaining the certificate correct data and format is very important. You need to add the following der certificate to your project:

openssl s_client -connect example.com:443 </dev/null |openssl x509 -outform DER -out example.der

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM