美文网首页服务端知识
AFNetworking实现HTTPS

AFNetworking实现HTTPS

作者: 优雨 | 来源:发表于2018-01-23 19:22 被阅读98次

在AFNetworking中,和HTTPS相关的类是AFSecurityPolicy,和其相关的属性和方法主要有以下几个

1.validatesDomainName

这个属性声明了客户端是否去验证证书中域名这个字段,默认为YES

2.allowInvalidCertificates

这个属性声明了客户端是否信任不可用或者过期的证书,默认为NO

3.SSLPinningMode

这个属性声明了客户端如何去校验服务器端给予的证书,默认为AFSSLPinningModeNone

typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {
    AFSSLPinningModeNone,
    AFSSLPinningModePublicKey,
    AFSSLPinningModeCertificate,
};
  • AFSSLPinningModeNone 这个是默认值。当allowInvalidCertificates为YES时,客户端无条件信任服务器返回的证书,否则,会去查询iOS包含的CA根证书列表进行校验。
  • AFSSLPinningModePublicKey 只验证客户端证书中包含的公钥,不验证证书的有效期等信息。
  • AFSSLPinningModeCertificate 不仅验证公钥,也会验证证书本身的有效期等信息

推荐将这个属性设置为AFSSLPinningModePublicKey,因为如果证书一单过期,就需要手动更新APP进行证书的更新。一般来说,只要公钥正确就能够保证通信是安全的,因为中间人无私钥,无法解开公钥加密的数据,也就无法获取到session key。

示例:

AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey withPinnedCertificates:cer];
securityPolicy.validatesDomainName = YES;
securityPolicy.allowInvalidCertificates = NO;
self.securityPolicy = securityPolicy;

以上方法对于实现HTTPS来说已经足够了。

自定义验证

- (void)setSessionDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;

AFURLSessionManager提供的setSessionDidReceiveAuthenticationChallengeBlock:方法实际上是对NSURLSessionDelegate的代理方法URLSession:didReceiveChallenge:completionHandler:的封装。当走HTTPS的时候,该代理方法会收到一个challenge(质询),需要你提供认证信息才能完成连接。这时候可以通过 challenge.protectionSpace.authenticationMethod取得保护空间要求我们认证的方式,如果这个值是 NSURLAuthenticationMethodServerTrust的话,我们就可以插手TLS握手中“验证数字证书有效性”这一步。这个方法AFNetworking提供了默认实现,如果我们要自定义验证过程,就需要调用setSessionDidReceiveAuthenticationChallengeBlock:方法来修改。

evaluateServerTrust:forDomain:

AFURLSessionManager提供的验证指定的ServerTrust和Domain是否可信任的方法。
ServerTrust代表服务器的SSL事务状态,可以由challenge.protectionSpace.serverTrust来拿到。

[self setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession * _Nonnull session, NSURLAuthenticationChallenge * _Nonnull challenge, NSURLCredential *__autoreleasing  _Nullable * _Nullable credential) {
            __strong typeof(weakSelf) strongSelf = weakSelf;
            NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
            if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
                if ([securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
                    NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
                    if (credential) {
                        disposition = NSURLSessionAuthChallengeUseCredential;
                    } else {
                        disposition = NSURLSessionAuthChallengePerformDefaultHandling;
                    }
                } else {
                    disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
                }
            } else {
                disposition = NSURLSessionAuthChallengePerformDefaultHandling;
            }
            //以上调用的是系统默认实现
            if (disposition == NSURLSessionAuthChallengeCancelAuthenticationChallenge) {
                //证书不可用 自定义验证过程
                BOOL expired = YES;
                if (@available(iOS 10, *)) {
                    for (NSData *certData in strongSelf.securityPolicy.pinnedCertificates) {
                        BOOL theExpired = [strongSelf session:session cert:certData didReceiveAuthenticationChallenge:challenge];//验证证书是否全部过期
                        expired = expired && theExpired;
                    }
                } else {
                    // SecTrustEvaluate 在iOS9 及以下会发生crash,暂停使用
                    expired = NO;
                }
                
                // 证书全部过期,提示升级
                if (expired) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [strongSelf handleSSLError:handler overdue:YES];
                    });
                } else {
                    dispatch_async(dispatch_get_main_queue(), ^(void){
                        [strongSelf handleSSLError:handler overdue:NO];
                    });
                }
            }
            return disposition;
        }];

相关文章

网友评论

    本文标题:AFNetworking实现HTTPS

    本文链接:https://www.haomeiwen.com/subject/xokeaxtx.html