AFNetworking 原作者都无法解决的问题: 如何使用ip直接访问https网站?

背景

最近App似乎有报异常是DNS无法解析,尝试解决此问题.搜集到的资料很少,甚至连AFN原作者都判定这可能是一个无解的问题,参见: https://github.com/AFNetworking/AFNetworking/issues/2954,不过最终还是靠着stackoverflow上的一丁点提示,顺利找到并汇集成了一个可用的解决方案.大喜,与君共享!

问题描述

通过IP直接访问网站,可以解决DNS劫持问题.DNS劫持,可以通过修改电脑的host文件模拟.如果是HTTP请求,使用ip地址直接访问接口,配合header中Host字段带上原来的域名信息即可;如果是 https请求,会很麻烦,需要 Overriding TLS Chain Validation Correctly;curl 中有一个 -resolve 方法可以实现使用指定ip访问https网站,iOS中集成curl库应该也可以,不过改动太大,未验证;对于服务器IP经常变的情况,可能需要使用httpDNS服务,参见:https://www.dnspod.cn/httpdns.

解决方案讨论

1. 最直接的方式是允许无效的SSL证书,生产环境不建议使用;

2.一个需要部分重写AFN源码的方法.

  • 在Info.plist中添加NSAppTransportSecurity类型Dictionary,在NSAppTransportSecurity下添加NSAllowsArbitraryLoads类型Boolean,值设为YES.这些本来是用来解决iOS9下,允许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

    willSendRequestForAuthenticationChallenge:(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/.

时间: 2024-10-30 10:32:44

AFNetworking 原作者都无法解决的问题: 如何使用ip直接访问https网站?的相关文章

解决Chrome浏览器不能访问https网站的问题

使用Chrome访问https网站时,可能会出现以下错误,本文说明如何解决此类问题: "您的连接不是私密连接"."NET::ERR_CERT_AUTHORITY_INVALID"."ERR_CERT_COMMON_NAME_INVALID"或"NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM" 方法/步骤 参考下面经验,将Chrome升级到最新版本,看是否可以解决这些问题,如果问题没有解决,则再尝试

解决python2.7.9以下版本requests访问https的问题

在python2.7.9以下版本requests访问https连接后,总会报一些关于SSL warning. 解决法子可以参考:https://urllib3.readthedocs.io/en/latest/security.html#insecureplatformwarning (链接里面还包含各种其他问题的解决法子) ----- 按照里面的做法, 1.更新python的版本 到官网https://www.python.org/downloads/release/python-2711/ 

部分手机无法访问https网站解决办法

思想: 最小化操作,对于不熟悉的参数,在不影响使用的前提下,暂时先注销其功能. 发生错误时,先分析产生问题的界限,对于涉及到该界限的擦参数进行处理. 参考实例: 升级了nginx版本后,将原有的配置文件全部复制到新的目录下,出现部分手机(主要是华为手机自带浏览器)无法访问 https网址,在比对配置,降级等操作后,发现新版本的(ssl_prefer_server_ciphers on;)的参数与旧版本的参数不一致. 关闭该参数后,操作恢复了正常. 原文地址:http://blog.51cto.c

【fastweixin框架教程3】JAVA进行HTTPS网站访问,PKIX path building failed解决方法

上几篇文章我们谈到fastweixin使用问题和修改. 今天的问题就是使用JAVA访问HTTPS网站时候经常出现javax.net.ssl.SSLHandshakeException javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderEx

解决Chrome浏览器访问https提示“您的连接不是私密连接”的问题

安装fiddler后,使用Chrome访问https网站时,可能会出现以下错误,本文说明如何解决此类问题: "您的连接不是私密连接"."NET::ERR_CERT_AUTHORITY_INVALID"."ERR_CERT_COMMON_NAME_INVALID"或"NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM" Step 1: 找到Chrome浏览器的快捷方式,选中该快捷方式,按下鼠标右键,在弹

火狐浏览器 访问所有HTTPS网站显示连接不安全解决办法

当 Firefox 连接到一个安全的网站时(网址最开始为“https://”),它必须确认该网站出具的证书有效且使用足够高的加密强度.如果证书无法通过验证,或加密强度过低,Firefox 会中止连接到这个网站,并显示“连接不安全”的错误信息页面. 点击 高级 按钮可以查看更多信息,了解为何此连接不安全.如果用户访问的是常见网站均出现这个错误:例如百度.淘宝.Mozilla 官方网站等,并显示错误信息为 SEC_ERROR_UNKNOWN_ISSUER 则很有可能是系统被导入了一个未知的根证书.由

容器私有云和持续发布都要解决哪些基础问题 第二集

郑昀编著 创建于2015/10/30 最后更新于2015/11/20 关键词:Docker,容器,持续集成,持续发布,私有云,Jenkins,Mesos,Marathon 本文档适用人员:广义上的技术人员 提纲: 集装箱还是卷挂载? Host Networking 还是 Bridge Networking? 容器要固定IP吗? 容器内部如何获取宿主机的IP? 容器日志如何收集? Apache Mesos 还是 Google K8s? 如何保证 Registry 镜像Pull/Push安全? 如何

IIS中访问自己开发的Webservice site就自动停止,尝试重启IIS和重启服务器都不能解决。

今天在加班的时候发现一个奇怪的问题,IIS里面我们自己开发的Webservice site一访问就自动停止.尝试重启IIS和重启服务器都不能解决.后台windows events报错信息是The Module DLL C:\Windows\System32\inetsrv\HipIISEngineStub.dll failed to load.  The data is the error. 后来找到了解决办法我也试了很好用. 1.用管理员身份打开C:\Windows\System32\inet

是不是所有的问题都有解决办法!唯有……

      2009年刚上大学的我欣喜的买了个联想笔记本电脑SL400,当时这款电脑刚出不久5700元,09年的5700对于一个农村的孩子来说真的不少,不知道是出于高兴还是出于高兴!可是想不到电子产品淘汰的这么快,短短几年的时间,价值5700的电脑二手只值400左!       说实话真的舍不得卖,可是留着又没用,更加贬值,思来想去,在同城二手市场发布打算卖出去,结果400竟然还有人跟我还价!可见当今社会二手货真的不值钱,一生气也没卖,由于做编程的,这个配置的电脑连eclipse起来都费劲,作为