iOS Objective C HTTPS请求失败

时间:2016-01-25 22:11:15

标签: ios objective-c nsurlconnection nsurl app-transport-security

我已经进行了广泛的搜索,并进行了必要的更改(我认为)以符合Appl的ATS限制。

私钥2048位或更高

openssl rsa -in privkey.pem -text -noout

私钥:(2048位)

在nginx上运行ssl v1.2 ssl verified at v1.2

甚至运行make nscurl实用程序来检查连接,所有测试都通过了。

我还可以通过从浏览器对https进行GET并使一切正常工作来验证服务器是否正常运行。

我虽然可能是子域名导致问题,所以我将info.plist文件更新为以下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"       "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>boramash.com</key> (also tried gateway.boramash.com)
        <dict>
            <key>NSIncludesSubdomains</key>
            <true/>
        </dict>
    </dict>
</dict>

我认为一切正常,我会遇到以下错误。

  

2016-01-25 15:59:17.345 StripePlayground [2999:84984]   NSURLSession / NSURLConnection HTTP加载失败   (kCFStreamErrorDomainSSL,-9802)2016-01-25 15:59:17.348   StripePlayground [2999:84989](null)2016-01-25 15:59:17.348   StripePlayground [2999:84989]错误域= NSURLErrorDomain代码= -1200   &#34;发生SSL错误并与服务器建立安全连接   无法制作。&#34;   UserInfo = {NSURLErrorFailingURLPeerTrustErrorKey =,NSLocalizedRecoverySuggestion =你想要吗?   无论如何连接到服务器?,_kCFStreamErrorDomainKey = 3,   _kCFStreamErrorCodeKey = -9802,NSErrorPeerCertificateChainKey = {type = immutable,count = 1,values =(     0:)},NSUnderlyingError = 0x7fd97252e580 {错误   Domain = kCFErrorDomainCFNetwork Code = -1200&#34;(null)&#34;   的UserInfo = {_ kCFStreamPropertySSLClientCertificateState = 0,   kCFStreamPropertySSLPeerTrust =,   _kCFNetworkCFStreamSSLErrorOriginalValue = -9802,_kCFStreamErrorDomainKey = 3,_kCFStreamErrorCodeKey = -9802,kCFStreamPropertySSLPeerCertificates = {type = immutable,count = 1,values =(0:    }}}},NSLocalizedDescription =发生了SSL错误   并且无法与服务器建立安全连接。   NSErrorFailingURLKey = https://gateway.boramash.com/stripe-add-customer,   NSErrorFailingURLStringKey =   prependingtext_for_stack_overflowhttps://gateway.boramash.com/stripe-add-customer,   NSErrorClientCertificateStateKey = 0}

这也是我的要求制作代码,非常基本。

NSString *myrequest = @"https://gateway.boramash.com/stripe-add-customer";

// NSURL *newcustomerURL = [NSURL URLWithString:@"http//45.55.154.107:5050/create-customer"];
NSURL *newcustomerURL = [NSURL URLWithString: myrequest];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: newcustomerURL];
//request.HTTPBody = [[NSString stringWithFormat:@"customer_id=%@&first_name=%@&last_name=%@", testID, firstName, lastName] dataUsingEncoding: NSUTF8StringEncoding ];

request.HTTPMethod = @"GET";

[[[NSURLSession sharedSession] dataTaskWithRequest:request    completionHandler:^(NSData * _Nullable data, NSURLResponse *_Nullable  response, NSError * _Nullable error) {
    //print the result here - new customer has been created!
    NSString *myresponse = [NSString stringWithFormat:@"%@", response];
    NSString *myerror = [NSString stringWithFormat:@"%@", error];

    NSLog(@"%@", myresponse);
    NSLog(@"%@", myerror);
}] resume];

非常感谢任何建议!

3 个答案:

答案 0 :(得分:1)

问题不在于ATS,问题是您在向https://gateway.boramash.com/发出GET请求时收到无效的SSL证书...

要在不替换后端证书的情况下通过此操作,您需要实现以下委托方法:

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler;

以下是一个例子:

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {
    if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
        NSString *host = challenge.protectionSpace.host;
        NSArray *acceptedDomains = @[@".boramash.com$"];
        BOOL accept = NO;

        for (NSString *pattern in acceptedDomains)
        {
            NSRange range = [host rangeOfString:pattern options:NSCaseInsensitiveSearch|NSRegularExpressionSearch];
            if (range.location != NSNotFound)
            {
                accept = YES;
                break;
            }
        }

        if (accept)
        {
            NSLog(@"%@", [NSString stringWithFormat:@"WARNING: accepting an invalid certificate from host: %@", host]);
            NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
        }
        else
        {
            NSLog(@"%@", [NSString stringWithFormat:@"WARNING: discarding an invalid certificate from host: %@", host]);
        }
    }
}

答案 1 :(得分:1)

TL; DR:由于某种原因,您的服务器不是(总是?)发送中间证书。检查服务器配置和证书/中间证书格式(检查日志中的错误,并检查服务器是否已正确重新启动)。

您可以使用openssl s_client -connect gateway.boramash.com:443检查命令行。

目前返回:

depth=0 CN = gateway.boramash.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = gateway.boramash.com
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
 0 s:/CN=gateway.boramash.com
   i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X1

...

    Verify return code: 21 (unable to verify the first certificate)

这意味着它找不到证书来验证证书上的签名。

您希望它返回:

depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X1
verify return:1
depth=0 CN = gateway.boramash.com
verify return:1
---
Certificate chain
 0 s:/CN=gateway.boramash.com
   i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X1

...

    Verify return code: 0 (ok)

(这是通过下载中间证书并使用-CAfile lets-encrypt-x1-cross-signed.pem将其提供给openssl获得的。)

您还可以通过添加-showcerts验证中间证书确实未发送。

奇怪的是,它确实适用于Safari(对我而言),虽然它在Firefox中不起作用。不太确定是什么产生了差异(可能是中间证书是使用来自同一CA的证书从另一个请求缓存到正确配置的服务器),但要仔细检查您的服务器配置(以及证书文件的格式),直到openssl喜欢它,iOS也应该喜欢它。

答案 2 :(得分:0)

尝试添加NSExceptionAllowsInsecureHTTPLoads并设置true