iOS Objective C HTTPS 请求失败

iOS Objective C HTTPS request failing

我进行了广泛的搜索并进行了必要的更改(我认为)以符合 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 load failed (kCFStreamErrorDomainSSL, -9802) 2016-01-25 15:59:17.348 StripePlayground[2999:84989] (null) 2016-01-25 15:59:17.348 StripePlayground[2999:84989] Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, NSErrorPeerCertificateChainKey={type = immutable, count = 1, values = ( 0 : )}, NSUnderlyingError=0x7fd97252e580 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, kCFStreamPropertySSLPeerCertificates={type = immutable, count = 1, values = ( 0 : )}}}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., 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];

如有任何建议,我们将不胜感激!

尝试添加 NSExceptionAllowsInsecureHTTPLoads 并设置 true

问题不是 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]);
        }
    }
}

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

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

目前 returns:

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)

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

你想要它 return:

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 的证书从另一个请求缓存到正确配置的服务器),但是 double-check 您的服务器配置(以及证书文件的格式)直到openssl 喜欢,iOS 应该也喜欢。