AFNetworkingの原作者が解決できない問題:ipを使用してhttpsサイトに直接アクセスする方法

4566 ワード

背景


最近AppはDNSが解析できないという異常を報告しているようで、この問題を解決しようとしている.収集された資料は少なく、AFNの原作者さえこれが無解な問題である可能性があると判断している.https://github.com/AFNetworking/AFNetworking/issues/2954しかし、最終的にはstackoverflowのヒントに頼って、利用可能なソリューションを順調に見つけて統合しました.大喜び、君とシェア!

問題の説明


IPを介して直接ウェブサイトにアクセスすることで、DNSハイジャック問題を解決することができる.DNSハイジャックは、コンピュータのhostファイルシミュレーションを修正することができます.HTTPリクエストの場合、ipアドレスを使用してインタフェースに直接アクセスし、headerのHostフィールドに合わせて元のドメイン名情報を持ち込めばよい.httpリクエストであれば面倒ですが、Overriding TLS Chain Validation Correctlyが必要です.curlには-resolveの方法があり、指定されたipを使用してhttpサイトにアクセスすることができます.iOSにcurlライブラリを統合してもいいはずですが、変更が大きすぎて検証されていません.サーバIPが頻繁に変化する場合、httpDNSサービスを使用する必要がある場合があります.https://www.dnspod.cn/httpdns.

ソリューションの検討


1.最も直接的な方法は無効なSSL証明書を許可することであり、生産環境は使用を推奨しない。


2.AFNのソースコードを部分的に書き換える必要がある方法.

  • はInfo.plistにNSAppTransportSecurityタイプDictionaryを追加し、NSAppTransportSecurityの下にNSAllowsArbitraryLoadsタイプBooleanを追加し、値をS.YEに設定これらは、iOS 9において、HTTP要求によるネットワークへのアクセスを許可するためのものであるが、これらに限らない.具体的な原因は自分でgoogle.
  • AFURLConnectionOperationクラスに新しい属性を追加:
  • /**  , ip https .
     Trusted domain, this domain for support via IP access HTTPS links.
     */
    @property(nonatomic, strong) NSMutableArray * trustHostnames;
  • AFURLConnectionOperationに実装されるエージェントメソッド:-(void)connection:(NSURLConnection)connection willS endRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge)challenge信頼できるドメイン名を追加する関連論理コード:
  • - (void)connection:(NSURLConnection *)connection
    willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
    {
        if (self.authenticationChallenge) {
            self.authenticationChallenge(connection, challenge);
            return;
        }
        
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
            
            /*  , : ip https .
             Add trusted domain name to support: direct use of IP access specific HTTPS server.*/
            for (NSString * trustHostname  in [self trustHostnames]) {
                serverTrust = AFChangeHostForTrust(serverTrust, trustHostname);
            }
    
        ....
  • Appleの公式ドキュメントを参照して、信頼できるドメイン名を追加する関数をカスタマイズします:AFChangeHostForTrust
  • static inline SecTrustRef AFChangeHostForTrust(SecTrustRef trust, NSString * trustHostname)
    {
        if ( ! trustHostname || [trustHostname isEqualToString:@""]) {
            return trust;
        }
        
        CFMutableArrayRef newTrustPolicies = CFArrayCreateMutable(
                                                                  kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
        
        SecPolicyRef sslPolicy = SecPolicyCreateSSL(true, (CFStringRef)trustHostname);
        
        CFArrayAppendValue(newTrustPolicies, sslPolicy);
        
        
    #ifdef MAC_BACKWARDS_COMPATIBILITY
        /* This technique works in OS X (v10.5 and later) */
        
        SecTrustSetPolicies(trust, newTrustPolicies);
        CFRelease(oldTrustPolicies);
        
        return trust;
    #else
        /* This technique works in iOS 2 and later, or
         OS X v10.7 and later */
        
        CFMutableArrayRef certificates = CFArrayCreateMutable(
                                                              kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
        
        /* Copy the certificates from the original trust object */
        CFIndex count = SecTrustGetCertificateCount(trust);
        CFIndex i=0;
        for (i = 0; i < count; i++) {
            SecCertificateRef item = SecTrustGetCertificateAtIndex(trust, i);
            CFArrayAppendValue(certificates, item);
        }
        
        /* Create a new trust object */
        SecTrustRef newtrust = NULL;
        if (SecTrustCreateWithCertificates(certificates, newTrustPolicies, &newtrust) != errSecSuccess) {
            /* Probably a good spot to log something. */
            
            return NULL;
        }
        
        return newtrust;
    #endif
    }
  • AOPメソッドを使用して、AFURLConnectionOperationのtrustHostnamesプロパティを書き換える:
  •     /*  AOP , ,  : ip https .*/
        [AFURLConnectionOperation aspect_hookSelector:@selector(trustHostnames) withOptions:AspectPositionInstead usingBlock: ^(id<AspectInfo> info){
            __autoreleasing NSArray * trustHostnames = @[@"www.example.com"];
            
            NSInvocation *invocation = info.originalInvocation;
            [invocation setReturnValue:&trustHostnames];
        }error:NULL];
    

    ここではiOS AOPライブラリを使用しています.よく知らない点はここです.http://www.ios122.com/2015/08/aspects/.