0

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

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

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 请求时,我收到此错误:

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

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

我知道为 NSURLRequest 添加委托方法,但这些方法从未被调用并被认为是解决此问题的多余方法。

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

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

谢谢,我希望这在解决后能帮助更多的开发人员。

4

2 回答 2

1

解决方案。感谢评论中的每个人都为我指明了正确的方向。解决方案是为这种特殊情况创建一个处理 NSURLRequests 的 NSObject。

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

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

所以,

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

BWWebService.h

#import <Foundation/Foundation.h>

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

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

@end

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

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

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

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

感谢大家。

编辑:看来这个解决方案的应用程序只适用于允许任意负载设置为 YES。

于 2016-02-04T18:30:40.177 回答
0

打开 Xcode,Command-Shift-2,输入 9813,你会立即找到 -9813 = errSSLNoRootCert,这是意料之中的,因为你的自签名证书没有根证书,而 -9802 = errSSLFatalAlert(你真的搞砸了)。

问题似乎是出于安全原因,某些软件不喜欢自签名证书。这通常可以通过创建和安装您自己的根证书并使用您自己的根证书签名的证书来解决。

于 2016-02-04T17:34:39.713 回答