iOS 9 ATS 使用自签名证书阻止对服务器的 HTTPS 请求 [英] iOS 9 ATS blocking HTTPS request to server with Self-Signed Certficate

查看:120
本文介绍了iOS 9 ATS 使用自签名证书阻止对服务器的 HTTPS 请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题是关于 Stack Overflow 的,过去 2 天我一直在尝试无数的 ATP 配置组合并使我的应用程序正常工作.我将彻底解决我的问题,因为看起来最微小的事情都会影响如何解决这个问题.

This issue is all over Stack Overflow and I have spent the past 2 days trying countless combinations of ATP configurations and getting my app to work. I'm going to be thorough with my problem as it appears the tiniest thing can affect how to resolve this.

我最近刚刚设置了一个启用了 SSL 和 TLS 1.2 的 Ubuntu 14 服务器.在我的服务器上是我的应用程序所依赖的服务器端脚本.在我的应用程序中,我使用 NSMutableURLRequest 从服务器请求我的 API,如下所示:

I have just recently set up an Ubuntu 14 server with SSL and TLS 1.2 enabled. On my server are my server-side scripts which my app depends on. In my app I use a NSMutableURLRequest to request my API from the server like so:

NSString * noteDataString = [NSString stringWithFormat:@"email=%@&password=%@&type=%@", companyEmail, companyPassword, @"login"];
NSData * postData = [noteDataString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString * postLength = [NSString stringWithFormat:@"%lu", (unsigned long)[postData length]];

NSMutableURLRequest * request = [[NSMutableURLRequest alloc] init];

[request setURL:[NSURL URLWithString:@"https://mydomain.me:443/path/to/file.php"]];

[request setHTTPMethod:@"POST"];

[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:postData];

NSHTTPURLResponse * urlResponse = nil;
NSError * error = nil;
NSData * responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&error];
NSString * result = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];

NSLog(@"Response Code: %ld", (long)[urlResponse statusCode]);

当我将 url 复制到 Chrome 中时,会显示正确的 PHP 返回值.在 iOS 9 上从 Xcode 7 请求时,我收到此错误:

When I copy the url into Chrome the correct PHP return is shown. When requesting from Xcode 7 on iOS 9 I get this error:

NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)

我在类似问题中使用了无数的 info.plist 设置.我尝试禁用前向保密的需要,我尝试启用任意加载,我尝试使用异常域 mydomain.me 及其子域.我取得的唯一进展是错误代码 -9813 切换到 -9802.

I have used countless info.plist settings as seen across similar issues. I have tried disabling the need for forward secrecy, I have tried enabling arbitrary loads, I have tried using the exception domain mydomain.me and its subdomains. The only progress I achieve is an error code -9813 switching to -9802.

我知道为 NSURLRequest 添加委托方法,但这些方法从来没有被调用过,并被假定为解决这个问题是多余的.

I am aware of adding delegate methods for NSURLRequest but these are never called and assumed redundant for solving this problem.

我使用 localhost 和 http 在 MAMP 服务器上构建了很多应用程序,然后当我启用任意加载时请求工作,所以我的 plist 没有问题.

I built a lot of the app off a MAMP server using localhost and http and the requests worked when I enabled arbitrary loads then, so nothing wrong with my plist.

令人难以置信的是为什么我有一个特殊情况,我知道 Stack Overflow 是处理这种情况的地方!

It's mind-boggling onto why I have a special case, and I knew Stack Overflow was the place for such situations!

谢谢,我希望这能帮助我以外的更多开发人员解决.

Thanks, and I hope that this helps many more developers beyond me when solved.

推荐答案

解决方案.谢谢大家在评论中指出我正确的方向.解决方案是创建一个 NSObject 来处理这种特殊情况的 NSURLRequests.

Solution. Thank you everybody in the comments for pointing me in the right direction. The solution was to create an NSObject that handled NSURLRequests for this special case.

归功于:https://www.cocoanetics.com/2010/12/nsurlconnection-with-self-signed-certificates/

以下内容几乎是链接中教程的直接副本,但我认为留在这里会更容易.

The following is almost a direct copy from the tutorial in the link, but I figured it'd be easier to stay here.

所以,

我必须使用以下代码创建一个新的 NSObject 类:

I had to create a new NSObject class with the following code:

BWWebService.h

BWWebService.h

#import <Foundation/Foundation.h>

@interface BWWebService : NSObject{
    NSMutableData *receivedData;
    NSURLConnection *connection;
    NSStringEncoding encoding;
}

- (id)initWithURL:(NSURL *)url;

@end

BWWebService.m

BWWebService.m

#import "BWWebService.h"

@implementation BWWebService

- (id)initWithURL:(NSURL *)url{
    if (self = [super init]){
        NSURLRequest * request = [NSURLRequest requestWithURL:url];

        connection = [NSURLConnection connectionWithRequest:request delegate:self];

        [connection start];
    }

    return self;
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    // Every response could mean a redirect
    receivedData = nil;

    CFStringEncoding cfEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)
                                                                               [response textEncodingName]);
encoding = CFStringConvertEncodingToNSStringEncoding(cfEncoding);
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    if (!receivedData){
        // No store yet, make one
        receivedData = [[NSMutableData alloc] initWithData:data];
    }else{
        // Append to previous chunks
        [receivedData appendData:data];
    }
}

// All worked
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
    NSString * xml = [[NSString alloc] initWithData:receivedData encoding:encoding];
    NSLog(@"%@", xml);
}

// And error occurred
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
     NSLog(@"Error retrieving data, %@", [error localizedDescription]);
}

// To deal with self-signed certificates
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace{
    return [protectionSpace.authenticationMethod
        isEqualToString:NSURLAuthenticationMethodServerTrust];
}

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]){
        // we only trust our own domain
        if ([challenge.protectionSpace.host isEqualToString:@"myuntrusteddomain.me"]){
           NSURLCredential * credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            [challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
        }
    }

    [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
@end

如果这还不够,为了提出请求,我使用以下内容代替了我的原始请求:

And if that wasn't enough, to make the request I used the following in replacement of my original request:

NSURL * url = [NSURL URLWithString:@"https://myuntrusteddomain.me:443/path/to/script.php"];
BWWebService * webService;
webService = [[BWWebService alloc] initWithURL:url];

我知道这不会像原始数据那样 POST 数据,但稍后会出现.我确定这将是处理 initWithURL 中的 POST 的问题.

I know that this does not POST data like the original, but that comes later. I am sure it will be a matter of handling the POST in initWithURL.

谢谢大家.

看来该解决方案的此应用程序仅适用于将允许任意负载"设置为是"的情况.

It appears this application of the solution only works with Allows Arbitrary Loads set to YES.

这篇关于iOS 9 ATS 使用自签名证书阻止对服务器的 HTTPS 请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆