Почему я не могу переопределить SSL ServerTrust для NSURLSessionDataTask в службе XPC? - PullRequest
0 голосов
/ 02 октября 2019

Я пытаюсь выполнить HTTPS-запрос в службе XPC, используя NSURLSessionDataTask. Это сбой и даже ожидается сбой, поскольку сервер использует сертификат TLS, подписанный ЦС, неизвестным системе.

Итак, я реализовал протокол NSURLSessionDelegate, реализовал метод URLSession:didReceiveChallenge:completionHandler:,получил объект SecTrustRef, добавил сертификат CA к нему (который поставляется с моей службой XPC) и оценил доверие с помощью SecTrustEvaluate(). Если я сначала оцениваю без добавления своего ЦС, система говорит, что сертификат не является доверенным, если я делаю это после добавления ЦС, система говорит, что он является доверенным, поэтому, очевидно, я все делаю правильно. Наконец я звоню

NSURLCredential * credential = [NSURLCredential credentialForTrust:trust];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);

И соединение ... все равно не удается. И все равно происходит сбой с точно такой же ошибкой, как если бы я вообще не использовал этот делегат (NSURLErrorSecureConnectionFailed). Точно такой же код работал нормально в другом проекте. Даже когда я вообще ничего не оцениваю и просто реализую метод следующим образом:

- (void)URLSession:(NSURLSession *)session
    didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
    completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, 
        NSURLCredential * _Nullable))completionHandler
{
    NSString * method = challenge.protectionSpace.authenticationMethod;
    if (![method isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
        return;
    }

    SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
    if (!serverTrust) {
        completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
        return;
    }

    NSURLCredential * credential = [NSURLCredential credentialForTrust:serverTrust];
    completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
}

Соединение по-прежнему не работает с ошибкой NSURLErrorSecureConnectionFailed.

1 Ответ

0 голосов
/ 02 октября 2019

Оказывается, что, когда ATS (App Transport Security) активен, что является значением по умолчанию для всех приложений, связанных с SDK iOS 9.0 / macOS 11.0 или новее, NSURLSessionDelegate может только ужесточить ограничения безопасности, например, с помощью закрепления сертификата / открытого ключа, но он не может их ослабить , поскольку независимо от того, что говорит делегат, ATS «всегда сделает свое дело». Помимо принудительного использования HTTPS вместо HTTP, ATS также выполняет собственные проверки сертификатов.

Если вы хотите выполнить проверку сертификата самостоятельно, вам необходимо отключить ATS. Для этого вашему Info.plist требуется ключ NSAppTransportSecurity, значение которого является словарем и содержит логический ключ NSAllowsArbitraryLoads, установленный на YES.

Из документации:

NSURLSession обеспечивает безопасность транспорта приложений (ATS), если она включена для домена, к которому вы подключаетесь. Это относится к требованиям безопасности для сертификатов, версии TLS и шифра, используемых соединением. Вы не можете ослабить требования доверия к серверу для домена, защищенного ATS , но вы можете ужесточить их, используя технику оценки вручную, показанную в этой статье.

Источник: Выполнение ручной аутентификации доверия сервера

А также:

Без ATS вы также можно свободно ослаблять требования к доверию сервера по умолчанию, как описано в разделе Выполнение ручной аутентификации доверия к серверу.

Источник: Ключ списка свойств - NSAllowsArbitraryLoads

Примечание:
При отключении ATS для сборки App Store Apple требует от вас письменного обоснования того, почему ваше приложение действительно требует такого исключения, так что Apple

...