Определение доверия с NSURLConnection и NSURLProtectionSpace
Я хотел бы задать следующий вопрос ранее поставленный вопрос. У меня есть код для создания 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{...
Ответы
Ответ 1
Итак, я провел несколько дней, исследуя это. Похоже, что в то время как API NSURLConnection не может определить, доверен ли сертификат, существует такой метод в Security Framework, который передает это. Итак, вот код, который я придумал:
-(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 "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];
}
}
Ответ 2
Если результат kSecTrustResultConfirm
, вы должны спросить пользователя, является ли он надежным сервером.
Ответ 3
Ответ выше просто работает, если у вас есть доверенный сертификат CA, потому что в этом случае вы используете сертификаты CA, разрешенные Apple, для проверки.
Если у вас есть самозаверяющие сертификаты, вы должны использовать свой собственный сертификат сервера CA для проверки, действительно ли он...
Я нашел хороший (немного запутанный) здесь. Он охватывает слишком двойное рукопожатие....
Надеюсь, что это поможет!