CFNetwork SSLHandshake nie powiodło się iOS 9

207

czy ktoś z iOS 9 beta 1 miał ten problem?

Używam standardowego NSURLConnection, aby połączyć się z usługą internetową, a gdy tylko zostanie nawiązane połączenie z usługą internetową, pojawia się następujący błąd. Działa to obecnie w iOS 8.3

Możliwy błąd beta? wszelkie pomysły lub myśli byłyby świetne! Wiem, że to bardzo wcześnie w rozwoju iOS 9

Oto pełny błąd:

CFNetwork SSLHandshake nie powiodło się (-9824) Niepowodzenie ładowania HTTP NSURLSession / NSURLConnection HTTP (kCFStreamErrorDomainSSL, -9824)

 NSURLRequest * urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://mywebserviceurl"]];
        NSURLResponse * response = nil;
        NSError * error = nil;
        NSData * data = [NSURLConnection sendSynchronousRequest:urlRequest
                                                  returningResponse:&response
                                                              error:&error];
użytkownik3099837
źródło

Odpowiedzi:

310

iOS 9 i OSX 10.11 wymagają protokołu TLSv1.2 SSL dla wszystkich hostów, z których planujesz żądać danych, chyba że określisz domeny wyjątków w pliku Info.plist aplikacji.

Składnia konfiguracji Info.plist wygląda następująco:

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSExceptionDomains</key>
  <dict>
    <key>yourserver.com</key>
    <dict>
      <!--Include to allow subdomains-->
      <key>NSIncludesSubdomains</key>
      <true/>
      <!--Include to allow insecure HTTP requests-->
      <key>NSExceptionAllowsInsecureHTTPLoads</key>
      <true/>
      <!--Include to specify minimum TLS version-->
      <key>NSExceptionMinimumTLSVersion</key>
      <string>TLSv1.1</string>
    </dict>
  </dict>
</dict>

Jeśli Twoja aplikacja (na przykład przeglądarka internetowa innej firmy) musi połączyć się z dowolnymi hostami, możesz skonfigurować ją w następujący sposób:

<key>NSAppTransportSecurity</key>
<dict>
    <!--Connect to anything (this is probably BAD)-->
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

Jeśli musisz to zrobić, prawdopodobnie najlepiej zaktualizuj swoje serwery, aby korzystały z TLSv1.2 i SSL, jeśli jeszcze tego nie robią. Należy to uznać za tymczasowe obejście.

Na dzień dzisiejszy w dokumentacji przedpremierowej nie wspomniano o żadnej z tych opcji konfiguracji w żaden konkretny sposób. Kiedy to zrobię, zaktualizuję odpowiedź, aby połączyć się z odpowiednią dokumentacją.

Steven Peterson
źródło
1
App Transport Security (ATS) pozwala aplikacji dodać deklarację do pliku Info.plist, który określa domeny, z którymi potrzebuje bezpiecznej komunikacji. ATS zapobiega przypadkowemu ujawnieniu, zapewnia bezpieczne zachowanie domyślne i jest łatwy do przyjęcia. Powinieneś jak najszybciej zastosować ATS, niezależnie od tego, czy tworzysz nową aplikację, czy aktualizujesz już istniejącą. Jeśli opracowujesz nową aplikację, powinieneś używać wyłącznie HTTPS. Jeśli masz już istniejącą aplikację, powinieneś w tej chwili używać HTTPS i stworzyć plan jak najszybszej migracji reszty aplikacji.
user3099837,
2
@StevenPeterson hej steve i cant wydaje się, że nie działa przykład domeny wyjątków, czy masz jakieś pomysły przez przypadek, właśnie skopiowałem i wkleiłem do .plist zmieniono TLSv1.1 na TLSv1.0 i domenę do naszej domeny bez https: // etc
user3099837
27
Przepraszam za długi czat, ale zorientowałem się, że muszę wyłączyć <key> NSTemporaryExceptionRequiresForwardSecrecy </key> <false />
user3099837
2
@RashmiRanjanmallick NSTemporaryExceptionMinimumTLSVersion służy do poinformowania ATS, że pracujesz z serwerem innym niż 1.2. Na przykład użyj tego, jeśli próbujesz połączyć się z hostem korzystającym z TLS 1.0. Musisz również użyć NSTemporaryExceptionRequiresForwardSecrecy ustawionej na false, jak wskazano powyżej user3099837.
Womble,
2
ste.vn/2015/06/10/… - To jest blog, z którego pochodzi odpowiedź.
Sean Dev
66

W iOS 10+ ciąg TLS MUSI mieć postać „TLSv1.0”. Nie może to być po prostu „1.0”. (Westchnienie)


Działa następująca kombinacja innych odpowiedzi.

Powiedzmy, że próbujesz połączyć się z hostem (YOUR_HOST.COM), który ma tylko TLS 1.0.

Dodaj je do Info.plist swojej aplikacji

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>YOUR_HOST.COM</key>
        <dict>
            <key>NSIncludesSubdomains</key>
            <true/>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <key>NSTemporaryExceptionMinimumTLSVersion</key>
            <string>TLSv1.0</string>
            <key>NSTemporaryExceptionRequiresForwardSecrecy</key>
            <false/>
        </dict>
    </dict>
</dict>
Womble
źródło
9
Wygląda na to, że dodawanie NSTemporaryExceptionRequiresForwardSecrecypomogło mi, dzięki!
Josh Valdivieso
2
Ta wersja nie działała dla mnie na iOS9.1 - musiałem użyć formatu ciągu TLSVersion w jednej z pozostałych odpowiedzi <key> NSTemporaryExceptionMinimumTLSVersion </key> <string> TLSv1.1 </string>
300baud
To działa, ale moje pytanie brzmi: czy to oznacza, że ​​moja aplikacja nie używa ssl, gdy te parametry są włączone i dane nie są szyfrowane?
DC
33

Aby uzyskać więcej informacji Konfigurowanie wyjątków bezpieczeństwa transportu aplikacji w iOS 9 i OSX 10.11

Co ciekawe, zauważysz, że połączenie próbuje zmienić protokół HTTP na https, aby zabezpieczyć się przed błędami w kodzie, w których mógłbyś przypadkowo błędnie skonfigurować adres URL. W niektórych przypadkach może to faktycznie działać, ale jest także mylące.

Ta wysyłka aplikacji z aplikacją Transport Transport Security obejmuje kilka dobrych wskazówek dotyczących debugowania

Awaria ATS

Większość awarii ATS będzie prezentowana jako błędy CFE z kodem z serii -9800. Są one zdefiniowane w nagłówku Security / SecureTransport.h

2015-08-23 06:34:42.700 SelfSignedServerATSTest[3792:683731] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)

CFNETWORK_DIAGNOSTICS

Ustaw zmienną środowiskową CFNETWORK_DIAGNOSTICS na 1, aby uzyskać więcej informacji o awarii na konsoli

nscurl

Narzędzie będzie działało przez kilka różnych kombinacji wyjątków ATS, próbując bezpiecznego połączenia z danym hostem w ramach każdej konfiguracji ATS i raportując wynik.

nscurl --ats-diagnostics https://example.com
onmyway133
źródło
1
Wskaż tylko, że nscurl jest dostępny tylko w Mac OS X „El Capitan”
webo80,
1
Jeszcze jedna wskazówka dotycząca debugowania, aby sprawdzić, który szyfr połączenia TLS jest używany przez twój serwer: curl -v https: // <nazwa_hosta>
André Morujão
1
Wszelkie pomysły na to, co może być przyczyną problemu, jeśli zwijaj wszystkie kroki w porządku?
Aston,
@ onmyway133 czy możesz dodać wyjaśnienie, w jaki sposób „Ustaw zmienną środowiskową CFNETWORK_DIAGNOSTICS na 1”?
YakirNa
1
@YakirNa możesz przeczytać o tym, jak to zrobić tutaj nshipster.com/launch-arguments-and-environment-variables to dość proste :)
onmyway133
2

Jeśli Twój backend korzysta z bezpiecznego połączenia, otrzymasz NSURLSession

CFNetwork SSLHandshake failed (-9801)
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9801)

musisz sprawdzić konfigurację serwera, aby uzyskać wersję ATS i certyfikat SSL. Informacje:

Zamiast po prostu zezwalać na niezabezpieczone połączenie przez ustawienie NSExceptionAllowsInsecureHTTPLoads = YES, zamiast tego musisz zezwolić na obniżone bezpieczeństwo na wypadek, gdyby Twój serwer nie spełniał minimalnego wymagania (v1.2) dla ATS (lub lepiej naprawić stronę serwera).

Zezwolenie na obniżone bezpieczeństwo na jednym serwerze

<key>NSExceptionDomains</key>
<dict>
    <key>api.yourDomaine.com</key>
    <dict>
        <key>NSExceptionMinimumTLSVersion</key>
        <string>TLSv1.0</string>
        <key>NSExceptionRequiresForwardSecrecy</key>
        <false/>
    </dict>
</dict>

użyj klienta openssl do sprawdzenia certyfikatu i uzyskania konfiguracji serwera za pomocą klienta openssl:

openssl s_client  -connect api.yourDomaine.com:port //(you may need to specify port or  to try with https://... or www.)

.. znajdź na końcu

SSL-Session:
    Protocol  : TLSv1
    Cipher    : AES256-SHA
    Session-ID: //
    Session-ID-ctx: 
    Master-Key: //
    Key-Arg   : None
    Start Time: 1449693038
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)

Aplikacja Transport Transport Security (ATS) wymaga protokołu Transport Layer Security (TLS) w wersji 1.2.

Wymagania dotyczące łączenia za pomocą ATS:

Wymagania dotyczące połączenia usługi internetowej do korzystania z aplikacji App Transport Security (ATS) dotyczą serwera, szyfrów połączeń i certyfikatów, jak następuje:

Certyfikaty muszą być podpisane jednym z następujących rodzajów kluczy:

  • Bezpieczny klucz algorytmu skrótu 2 (SHA-2) o długości skrótu co najmniej 256 (to znaczy SHA-256 lub większej)

  • Klucz do kryptografii krzywej eliptycznej (ECC) o rozmiarze co najmniej 256 bitów

  • Klucz Rivest-Shamir-Adleman (RSA) o długości co najmniej 2048 bitów Niepoprawny certyfikat powoduje ciężką awarię i brak połączenia.

Następujące szyfry połączeń obsługują tajemnicę przekazywania (FS) i współpracują z ATS:

TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA

Aktualizacja: okazuje się, że openssl zapewnia tylko minimalną wersję protokołu Łącza Protokół: TLSv1

Idali
źródło
Pozostaje pytanie, czy można zinterpretować informacje o openssl, aby dowiedzieć się, czy serwer spełnia wymagania. Również protokół: TLSv1 może być wersją makora zamiast 1.x
Idali
Robię to ogólnie, na wypadek korzystania z portu
Idali
Odpowiedź pozostawia więcej pytań otwartych niż odpowiedzi. Wydaje się, że problemem mogą być mapowania między raportami openssl a dokumentacją Apple. Z wyjścia openssl nie można ustalić, czy TLS 1.2 jest obsługiwany. Odpowiedź nie pozwala również ustalić, czy obsługiwana jest Perfect Forward Secrecy.
zaph
2

Po dwóch dniach prób i niepowodzeń zadziałał dla mnie ten kod womble

z jedną zmianą, zgodnie z tym postem powinniśmy przestać używać podkluczy powiązanych ze słownikiem NSExceptionDomains tego rodzaju konwencji

  NSTemporaryExceptionMinimumTLSVersion

I użyj na nowej konwencji

  NSExceptionMinimumTLSVersion

zamiast.

dokumentacja jabłkowa

mój kod

<key>NSAppTransportSecurity</key>
    <dict>
        <key>NSExceptionDomains</key>
        <dict>
            <key>YOUR_HOST.COM</key>
            <dict>
                <key>NSExceptionAllowsInsecureHTTPLoads</key>
                <true/>
                <key>NSExceptionMinimumTLSVersion</key>
                <string>TLSv1.0</string>
                <key>NSExceptionRequiresForwardSecrecy</key>
                <false/>
                <key>NSIncludesSubdomains</key>
                <true/>
            </dict>
        </dict>
    </dict>
yehoni amran
źródło
1

Innym przydatnym narzędziem jest nmap (instalacja nmap nm)

nmap --script ssl-enum-ciphers -p 443 google.com

Daje wynik

Starting Nmap 7.12 ( https://nmap.org ) at 2016-08-11 17:25 IDT
Nmap scan report for google.com (172.217.23.46)
Host is up (0.061s latency).
Other addresses for google.com (not scanned): 2a00:1450:4009:80a::200e
PORT    STATE SERVICE
443/tcp open  https
| ssl-enum-ciphers: 
|   TLSv1.0: 
|     ciphers: 
|       TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (secp256r1) - A
|       TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
|       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
|     compressors: 
|       NULL
|     cipher preference: server
|   TLSv1.1: 
|     ciphers: 
|       TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (secp256r1) - A
|       TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
|       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
|     compressors: 
|       NULL
|     cipher preference: server
|   TLSv1.2: 
|     ciphers: 
|       TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (secp256r1) - A
|       TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (secp256r1) - A
|       TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (secp256r1) - A
|       TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (secp256r1) - A
|       TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (secp256r1) - A
|       TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (secp256r1) - A
|       TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (secp256r1) - A
|       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
|       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_AES_128_CBC_SHA256 (rsa 2048) - A
|       TLS_RSA_WITH_AES_128_GCM_SHA256 (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA256 (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_GCM_SHA384 (rsa 2048) - A
|     compressors: 
|       NULL
|     cipher preference: client
|_  least strength: C

Nmap done: 1 IP address (1 host up) scanned in 5.48 seconds
Ryan Heitner
źródło
bardzo przydatne do debugowania problemu z certyfikatem
Lopakhin
0

Ten błąd pojawiał się czasami w dziennikach, gdy korzystałem z błędnej / awariowej wersji Cordova na iOS. Zniknęło, gdy zaktualizowałem lub obniżyłem Cordova iOS.

Serwer, z którym się łączyłem, korzystał z protokołu TLSv1.2 SSL, więc wiedziałem, że to nie problem.

im3r3k
źródło
0

W .plistpliku projektu dodaj to uprawnienie:

<key>NSAppTransportSecurity</key>
<dict>
    <!--Connect to anything (this is probably BAD)-->
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>
Hiren Dhamecha
źródło
0

Składnia konfiguracji Info.plist

   <key>NSAppTransportSecurity</key>
   <dict>
   <key>NSExceptionDomains</key>
    <dict>
    <key>yourserver.com</key>
   <dict>
  <!--Include to allow subdomains-->
  <key>NSIncludesSubdomains</key>
  <true/>
  <!--Include to allow insecure HTTP requests-->
  <key>NSExceptionAllowsInsecureHTTPLoads</key>
  <true/>
  <!--Include to specify minimum TLS version-->
  <key>NSExceptionMinimumTLSVersion</key>
  <string>TLSv1.1</string>
   </dict>
 </dict>

ALOK KUMAR
źródło
0

Zaktualizowana odpowiedź (po WWDC 2016):

Aplikacje na iOS będą wymagać bezpiecznych połączeń HTTPS do końca 2016 roku. Próba wyłączenia ATS może spowodować, że Twoja aplikacja zostanie odrzucona w przyszłości.

App Transport Security, czyli ATS, to funkcja wprowadzona przez Apple w iOS 9. Gdy ATS jest włączony, wymusza łączenie aplikacji z usługami sieciowymi za pośrednictwem połączenia HTTPS, a nie niezabezpieczonego HTTP.

Programiści mogą jednak nadal wyłączać ATS i zezwalać aplikacjom na wysyłanie danych przez połączenie HTTP, jak wspomniano w powyższych odpowiedziach. Pod koniec 2016 r. Apple wprowadzi obowiązek korzystania z ATS dla wszystkich programistów, którzy chcą przesłać swoje aplikacje do App Store. połączyć

Paraneetharan Saravanaperumal
źródło
0

Testowane przeze mnie urządzenie miało nieprawidłowy czas. Kiedy więc próbowałem uzyskać dostęp do strony z certyfikatem, który wkrótce się skończy, odmówiłby dostępu, ponieważ urządzenie wygasło. Aby to naprawić, ustaw odpowiedni czas na urządzeniu!

Warpzit
źródło