CFNetwork SSLHandshakeがiOS 9で失敗しました


iOS 9 beta 1のユーザーにこの問題がありましたか?

私は標準のNSURLConnectionを使用してwebserviceに接続し、webサービスにコールが行われるとすぐに以下のエラーが表示されます。 これは現在iOS 8.3で動作しています

ベータバグの可能性がありますか? どんなアイデアや思考も素晴らしいでしょう! 私はiOS 9開発の初期段階を知っています

以下は完全なエラーです:

CFNetwork SSLHandshake failed(-9824)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];

Answers


iOS 9およびOSX 10.11では、アプリのInfo.plistファイルに例外ドメインを指定しない限り、データを要求するすべてのホストに対してTLSv1.2 SSLが必要です。

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>
</dict>

あなたのアプリケーション(例えばサードパーティのWebブラウザ)が任意のホストに接続する必要がある場合は、次のように設定することができます:

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

これを行う必要がある場合は、TLSv1.2とSSLを使用するようにサーバーを更新することをお勧めします。 これは一時的な回避策と見なされるべきです。

今日のリリース前のドキュメントでは、これらの設定オプションについては何も特定の方法で言及していません。 それが終わると、関連するドキュメントへのリンクを更新します。




** iOS 10ベータ版の重要なお知らせ**

iOS 10では、TLS文字列は "TLSv1.0"の形式でなければなりません。 それは単に "1.0"にすることはできません。 はい、これは信じられないほど愚かで、アプリを破るものです。 iOS開発へようこそ。

上記のアドバイスの次の組み合わせが機能します。

TLS 1.0しかないホスト(YOUR_HOST.COM)に接続しようとしているとします。

これらをあなたのアプリのInfo.plistに追加してください

<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>



詳細情報iOS 9およびOSX 10.11でのApp Transport Security Exceptionsの設定

不思議なことに、誤ってURLを誤って設定した可能性のあるコードの間違いから保護するために、接続がhttpプロトコルをhttpsに変更しようとしていることがわかります。 場合によっては、実際にはうまくいくかもしれませんが、混乱することもあります。

これは、アプリケーションの輸送セキュリティでの出荷はいくつかの良いデバッグのヒントをカバーしています

ATSの失敗

ほとんどのATSの失敗は-9800シリーズのコードでCFErrorsとして表示されます。 これらは、Security / SecureTransport.hヘッダーで定義されています

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

CFNETWORK_DIAGNOSTICS

コンソールに関する詳細情報を得るには、環境変数CFNETWORK_DIAGNOSTICSを1に設定します

nscurl

このツールは、ATS例外のいくつかの異なる組み合わせを実行し、各ATS構成の下で所定のホストに安全に接続し、結果を報告します。

nscurl --ats-diagnostics https://example.com



NSURLSessionを使用してバックエンドが安全な接続を使用する場合

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

特にATSのバージョンとSSL証明書を取得するには、サーバーの設定を確認する必要があります。Info:

NSExceptionAllowsInsecureHTTPLoads = YES設定することで、単にセキュリティ保護されていない接続許可する代わりに、サーバーがATSの最小要件(v1.2)を満たさない(またはサーバー側を修正する)方が望ましい場合に、

単一サーバーへのセキュリティの低下を許可する

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

opensslクライアントを使用して証明書を調査し、openssl clientを使用してサーバー設定を取得します。

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

..最後に気づく

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)

アプリケーショントランスポートセキュリティ(ATS)には、トランスポートレイヤセキュリティ(TLS)プロトコルバージョン1.2が必要です。

ATSを使用して接続するための要件:

App Transport Security(ATS)を使用するWebサービス接続の要件には、次のようなサーバー、接続暗号、および証明書が必要です。

証明書は、次のいずれかのタイプの鍵で署名する必要があります。

  • ダイジェスト長が256以上(SHA-256以上)のSecure Hash Algorithm 2(SHA-2)キー
  • 256ビット以上の楕円曲線暗号(ECC)キー

  • 長さが少なくとも2048ビットのRivest-Shamir-Adleman(RSA)キー無効な証明書はハードエラーになり、接続しません。

次の接続暗号は、前方秘密(FS)と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

アップデート:opensslは最小限のプロトコルバージョンしか提供していませんプロトコル:TLSv1 リンク




2日間の試行錯誤の後、私にとってうまくいったのは、この狼狽のコードです

1つの変更で、このポストによると、その種の条約のNSExceptionDomains辞書に関連するサブキーの使用をやめてください

  NSTemporaryExceptionMinimumTLSVersion

新条約での使用

  NSExceptionMinimumTLSVersion

代わりに。

リンゴのドキュメント

私のコード

<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>



もう1つの便利なツールはnmap(brew install nmap)

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

出力を与える

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



このエラーは、私がバギー/クラッシュしたCordova iOSバージョンを使用していたときにログに表示されていました。 私がcordova iOSをアップグレードまたはダウングレードしたとき、それはなくなった。

私が接続していたサーバーはTLSv1.2 SSLを使用していたので、問題ではないことは分かっていました。




プロジェクトの.plistファイルに次の権限を追加します。

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



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>




更新された回答(WWDC2016以降):

iOSアプリでは2016年末までに安全なHTTPS接続が必要になります。ATSをオフにすると、今後アプリが拒否される可能性があります。

App Transport Security(ATS)は、AppleがiOS 9で導入した機能です.ATSを有効にすると、セキュリティで保護されていないHTTPではなく、HTTPS接続を介してアプリが強制的にWebサービスに接続します。

しかし、開発者はATSをオフにして、上記の回答に記載されているように、アプリケーションがHTTP接続を介してデータを送信できるようにすることができます。 2016年末、AppleはApp Storeにアプリを提出したいすべての開発者にATSを必須とする予定です。 リンク




なぜそれはあまりにも複雑になりますか?

iOS開発ターゲットを設定する - 8.0

そしてCmd + Shift + K




私がテストしたデバイスに間違った時間が設定されていました。 だから、すぐに使い果たされる証明書を持つページにアクセスしようとしたときに、証明書は期限切れになっていたため、アクセスが拒否されてしまいました。 修正するには、デバイスの適切な時刻を設定してください!




info.plistを以下のように使用するか、iOS 9.2までの私の仕事をコピー&

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>NSAppTransportSecurity</key>
        <dict>
            <key>NSAllowsArbitraryLoads</key>
            <true/>
        </dict>

    <key>CFBundleDevelopmentRegion</key>
    <string>en</string>
    <key>CFBundleExecutable</key>
    <string>$(EXECUTABLE_NAME)</string>
    <key>CFBundleIdentifier</key>
    <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>$(PRODUCT_NAME)</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleShortVersionString</key>
    <string>1.0</string>
    <key>CFBundleSignature</key>
    <string>????</string>
    <key>CFBundleVersion</key>
    <string>1.0</string>
    <key>LSRequiresIPhoneOS</key>
    <true/>
    <key>UILaunchStoryboardName</key>
    <string>LaunchScreen</string>
    <key>UIMainStoryboardFile</key>
    <string>Main</string>
    <key>UIRequiredDeviceCapabilities</key>
    <array>
        <string>armv7</string>
    </array>
    <key>UISupportedInterfaceOrientations</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
        <string>UIInterfaceOrientationLandscapeLeft</string>
        <string>UIInterfaceOrientationLandscapeRight</string>
    </array>
    <key>UISupportedInterfaceOrientations~ipad</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
        <string>UIInterfaceOrientationPortraitUpsideDown</string>
        <string>UIInterfaceOrientationLandscapeLeft</string>
        <string>UIInterfaceOrientationLandscapeRight</string>
    </array>
</dict>
</plist>