使用NSURLConnection和NSURLProtectionSpace确定信任
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用NSURLConnection和NSURLProtectionSpace确定信任相关的知识,希望对你有一定的参考价值。
我想向 a previously posed question提出一个后续问题。我已经有了创建NSURLRequest / Connection的代码,运行它并调用了用于身份验证的回调方法。这是具体的代码:
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust] || [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodDefault];
}
-(void)connection:(NSURLConnection *)connection
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if ([challenge previousFailureCount] > 0) {
[[challenge sender] cancelAuthenticationChallenge:challenge];
NSLog(@"Bad Username Or Password");
badUsernameAndPassword = YES;
finished = YES;
return;
}
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
if (appDelegate._allowInvalidCert)
{
// Go ahead...trust me!
[challenge.sender useCredential:
[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust]
forAuthenticationChallenge: challenge];
}
else
{
TrustGenerator *tg = [[TrustGenerator alloc] init];
if ([tg getTrust:challenge.protectionSpace])
{
// Go ahead...trust me!
[challenge.sender useCredential:
[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust]
forAuthenticationChallenge: challenge];
}
else {
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
}
}
else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodDefault) {
NSURLCredential *newCredential = [NSURLCredential credentialWithUser:_username password:_password persistence:NSURLCredentialPersistenceNone];
[[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
}
}
我正在遇到的是“didReceiveAuthenticationChallenge”与“[challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]”一直被调用,即使我尝试连接的服务器上的证书是可信的(使用Verisign证书)。所以我看到的是我的应用程序总是提示最终用户信任,即使网站是可信任的。考虑到那个假设与中间人攻击的人发生什么相关的恶业,等等。我真正想要的是这样的代码:
if (appDelegate._allowInvalidCert)
{
// Go ahead...trust me!
[challenge.sender useCredential:
[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust]
forAuthenticationChallenge: challenge];
}
else if(The OS trusts the cert on the server)
{
[challenge.sender useCredential:
[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust]
forAuthenticationChallenge: challenge];
}
else{...
所以我花了几天时间研究这个。看起来虽然NSURLConnection API无法确定证书是否可信,但安全框架中有一种方法可以解决这个问题。所以这是我提出的代码:
-(void)connection:(NSURLConnection *)connection
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if ([challenge previousFailureCount] > 0) {
[[challenge sender] cancelAuthenticationChallenge:challenge];
NSLog(@"Bad Username Or Password");
badUsernameAndPassword = YES;
finished = YES;
return;
}
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
SecTrustResultType result;
//This takes the serverTrust object and checkes it against your keychain
SecTrustEvaluate(challenge.protectionSpace.serverTrust, &result);
if (appDelegate._allowInvalidCert)
{
[challenge.sender useCredential:
[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust]
forAuthenticationChallenge: challenge];
}
//When testing this against a trusted server I got kSecTrustResultUnspecified every time. But the other two match the description of a trusted server
else if(result == kSecTrustResultProceed || result == kSecTrustResultConfirm || result == kSecTrustResultUnspecified){
[challenge.sender useCredential:
[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust]
forAuthenticationChallenge: challenge];
}
else
{
//Asks the user for trust
TrustGenerator *tg = [[TrustGenerator alloc] init];
if ([tg getTrust:challenge.protectionSpace])
{
//May need to add a method to add serverTrust to the keychain like Firefox's "Add Excpetion"
[challenge.sender useCredential:
[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust]
forAuthenticationChallenge: challenge];
}
else {
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
}
}
else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodDefault) {
NSURLCredential *newCredential = [NSURLCredential credentialWithUser:_username password:_password persistence:NSURLCredentialPersistenceNone];
[[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
}
}
如果结果是kSecTrustResultConfirm
,您实际上应该询问用户它是否是受信任的服务器。
如果您拥有CA可信证书,则上述答案才有效,因为在这种情况下您使用Apple允许的CA证书进行验证。
如果您有自签名证书,则应使用自己的CA服务器证书来检查它是否有效...
我找到了一个好的(有点令人困惑)here。它涵盖了双握手......
希望有所帮助!
以上是关于使用NSURLConnection和NSURLProtectionSpace确定信任的主要内容,如果未能解决你的问题,请参考以下文章
使用 NSAutoreleasePool 和 NSURLConnection
NSMutableRequest 和 NSURLConnection 的最大超时时间