我有一台安装了自签名SSL证书的服务器。但是,一旦我调用以下方法,它就不会得到任何响应。一旦我将URL更改回http,它就可以工作。
- (void)getAccountInfoWithCompletion:(void (^)(NSDictionary *json_response, NSError *error))completion
{
NSURLRequest *request = [NSURLRequest requestWithURL:
[NSURL URLWithString:
[NSString stringWithFormat:@"%@/api/account/%d/get_info", BASE_HOST_URL_IP, [self getUserID]]
]];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error)
{
if (completion)
{
//completion(@"error", error);
}
} else {
NSString *response_string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSDictionary *json_object = [NSJSONSerialization JSONObjectWithData:[response_string dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
if (completion)
{
completion(json_object, error);
}
}
}];
}
我代表的原因是我可以在我的应用程序中使用自签名证书。以下教程是我正在使用的,但后来我意识到我无法使用completionHandler方法的委托。我需要保留completionHandler方法。
http://www.cocoanetics.com/2010/12/nsurlconnection-with-self-signed-certificates/
如果从SSL网站收到回复,我该怎么办?
答案 0 :(得分:3)
在您描述的情况下,您(几乎)必须使用委托。
这里发生的是sendAsynchronousRequest:queue:completion:
使用URL加载系统的默认行为。网址加载系统会看到您自签名的证书,无法对其进行验证,因此无法信任它 - 并且无法连接。您应该看到NSError传入完成处理程序,其中填充了有关该问题的信息。
这在Technote 2232: HTTPS Server Trust Evaluation
中有详细描述要允许自签名证书,除非您有办法让您的自签名证书受信任并存储在钥匙串中,否则您无法使用sendAsynchronousRequest:queue:completion:
- 在iOS上,这仅适用于受管设备。对于测试,仅用于测试,您可以使用private Apple API来更改默认信任行为。
对于生产代码,您必须实现NSURLConnectionDelegate,该NSURLConnectionDelegate处理评估服务器提供的凭据并允许您使用自签名证书。这也在技术说明2232中进行了描述(在高级别)。如果你没有正确实现这一点,你可能会在你的应用程序中创建一个安全漏洞 - 这会很糟糕,mmmmmk?
我不建议您遵循您引用的Cocoanetics帖子的指导。材料过时且质量有问题。请参阅NSURLConnectionDelegate的文档和提及的Technote 2232。如果您想了解有关移动应用程序的传输级安全性的更多信息,可以使用plenty of resources。
如果您仍然希望使用自签名证书,则可以实施SSL公钥固定,以使远程(自签名)公钥与存储在应用程序中的已知本地值相匹配。这比尝试仅匹配主机名要好得多。一些示例代码可以帮助您入门here
答案 1 :(得分:2)
ViewController.h:
@interface ViewController : UIViewController <NSURLSessionDelegate>
@end
ViewController.m:
- (void)getAccountInfoWithCompletion:(void (^)(NSDictionary *json_response, NSError *error))completion
{
NSURLRequest *request = [NSURLRequest requestWithURL:
[NSURL URLWithString:
[NSString stringWithFormat:@"%@/api/account/%d/get_info", BASE_HOST_URL_IP, [self getUserID]]
]];
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration ephemeralSessionConfiguration];
defaultConfigObject.requestCachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue: [NSOperationQueue mainQueue]];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
if (error == nil && data != nil)
{
NSString *response_string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSDictionary *json_object = [NSJSONSerialization JSONObjectWithData:[response_string dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
if (completion)
{
completion(json_object, error);
}
}
}];
[dataTask resume];
}
新的美丽委托方法让我们替换NSURLConnection的sendAsynchronousRequest方法(无法处理SSL)
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
{
NSString *host = challenge.protectionSpace.host;
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
if ([host rangeOfString:@"yourHost.net"].location != NSNotFound)
{
completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
}
else
{
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge,nil);
}
}
}