AFNetworking 原作者都无法解决的问题: 如何使用ip直接访问https网站?
来源:互联网 发布:史丹利快报的淘宝店 编辑:程序博客网 时间:2024/04/19 09:11
背景
最近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 *)connectionwillSendRequestForAuthenticationChallenge:(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/.
- AFNetworking 原作者都无法解决的问题: 如何使用ip直接访问https网站?
- 解决weblogic9无法使用IP访问的问题
- 解决无法通过ip访问服务器上的网站
- Android如何使用WebView访问https的网站
- Android如何使用WebView访问https的网站
- Android如何使用WebView访问https的网站
- 腾讯云服务器完美解决无法使用公网IP访问的问题
- 解决JBOSS服务器无法通过IP访问的问题
- 解决JBOSS服务器无法通过IP访问的问题
- 解决JBOSS服务器无法通过IP访问的问题
- 解决JBOSS服务器无法通过IP访问的问题
- 如何使网站可使用HTTPS访问
- 解决burp suite 使用chrome访问https失真的问题
- 解决无法从本机访问 SharePoint 网站的问题
- 解决eclipse中无法直接使用Base64Encoder的问题
- 解决eclipse中无法直接使用Base64Encoder的问题
- expect解决ssh无法使用shell直接登录的问题
- 解决eclipse中无法直接使用Base64Encoder的问题
- HDU-1005 Number Sequence && 51NOD-1126 求递推序列的第N项
- Java基础之-----集合框架
- Socket网络编程详解
- 迪杰斯特拉算法C++实现
- Python-装饰器以及对带有参数的装饰器的理解
- AFNetworking 原作者都无法解决的问题: 如何使用ip直接访问https网站?
- Codeforces 617C Watering Flowers 【暴力 数据范围】
- Java 包
- c中定义变量的内存分配顺序问题(极易错!!!)
- Codeforces 617A Elephant
- Codeforces 617B Chocolate
- Codeforces D Polyline
- C++链表
- HDOJ 5611 Baby Ming and phone number