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 应该也喜欢。
我进行了广泛的搜索并进行了必要的更改(我认为)以符合 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 应该也喜欢。