美文网首页
AFNetworking 中的客户端验证服务端

AFNetworking 中的客户端验证服务端

作者: Alfred的记录本 | 来源:发表于2017-07-24 23:23 被阅读0次

    为了防止中间人攻击,需要在客户端中内置SSL证书,来验证服务端证书的有效性。

    • AFNetworking 定义了AFSecurityPolicy类实现对服务端的配置管理,其中AFSSLPinningMode 中定义的AFSSLPinningModePublicKeyAFSSLPinningModeCertificate均需要客户端中内置服务器的SSL证书。
    typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {
        AFSSLPinningModeNone,//不需要任何验证
        AFSSLPinningModePublicKey,//验证公钥
        AFSSLPinningModeCertificate,//验证证书
    };
    

    另外,可通过如下命令获取服务端的证书。

    openssl s_client -connect ***.***.com.cn:443 </dev/null 2>/dev/null | openssl x509 -outform DER > https.cer
    
    • 类中主要定义了如下方法进行验证,注释中已经很明确。
    // 客户端通过本地证书或公钥对服务端进行验证
    - (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
                      forDomain:(NSString *)domain
    {
        if (domain && self.allowInvalidCertificates && self.validatesDomainName && (self.SSLPinningMode == AFSSLPinningModeNone || [self.pinnedCertificates count] == 0)) {
            // https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/OverridingSSLChainValidationCorrectly.html
            //  According to the docs, you should only trust your provided certs for evaluation.
            //  Pinned certificates are added to the trust. Without pinned certificates,
            //  there is nothing to evaluate against.
            //
            //  From Apple Docs:
            //          "Do not implicitly trust self-signed certificates as anchors (kSecTrustOptionImplicitAnchors).
            //           Instead, add your own (self-signed) CA certificate to the list of trusted anchors."
            NSLog(@"In order to validate a domain name for self signed certificates, you MUST use pinning.");
            return NO;
        }
    
        NSMutableArray *policies = [NSMutableArray array];
        if (self.validatesDomainName) {//如果需要验证domain
            //设置验证策略  那么就使用SecPolicyCreateSSL函数创建验证策略
            [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
        } else {
            //只验证x509标准的证书
            [policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
        }
        // 设置验证serverTrust 的策略, 告诉系统在验证serverTrust的时候考虑域名的正确性
        SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
    
        if (self.SSLPinningMode == AFSSLPinningModeNone) {
            //如果为AFSSLPinningModeNone,则要么不验证,要么只使用系统对证书进行验证
            return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust);
        } else if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) {
            //如果不允许无效证书,且系统没有验证通过serverTrust
            return NO;
        }
    
        switch (self.SSLPinningMode) {
            case AFSSLPinningModeNone:
            default:
                return NO;
            case AFSSLPinningModeCertificate: {
                NSMutableArray *pinnedCertificates = [NSMutableArray array];//存放客户端证书
                for (NSData *certificateData in self.pinnedCertificates) {
                    [pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
                }
                
                //给serverTrust设置锚点证书,即如果以后再次去验证serverTrust,会从锚点证书去找是否匹配。
                SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
                //用系统CA证书 验证serverTrust的有效性
                if (!AFServerTrustIsValid(serverTrust)) {
                    return NO;
                }
    
                // obtain the chain after being validated, which *should* contain the pinned certificate in the last position (if it's the Root CA)
                //获取服务端证书链
                NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
                
                for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
                    //如果本地证书 包含 在服务端证书链中
                    if ([self.pinnedCertificates containsObject:trustChainCertificate]) {
                        return YES;
                    }
                }
                
                return NO;
            }
            case AFSSLPinningModePublicKey: {
                NSUInteger trustedPublicKeyCount = 0;
                //获取服务端公钥链
                NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust);
    
                for (id trustChainPublicKey in publicKeys) {
                    for (id pinnedPublicKey in self.pinnedPublicKeys) {
                        if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)trustChainPublicKey, (__bridge SecKeyRef)pinnedPublicKey)) {
                            //验证公钥匹配的个数
                            trustedPublicKeyCount += 1;
                        }
                    }
                }
                return trustedPublicKeyCount > 0;
            }
        }
        
        return NO;
    }
    
    

    相关文章

      网友评论

          本文标题:AFNetworking 中的客户端验证服务端

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