NSURLConnection で作成された永続的な接続を破棄することは可能ですか? 永続的な接続を破棄して、別の SSL ハンドシェイクを実行できるようにする必要があります。
今のところ、[conn cancel] を呼び出すと、そのホストへの次の接続要求で使用される永続的な接続が残されますが、これは望ましくありません。
NSURLConnection で作成された永続的な接続を破棄することは可能ですか? 永続的な接続を破棄して、別の SSL ハンドシェイクを実行できるようにする必要があります。
今のところ、[conn cancel] を呼び出すと、そのホストへの次の接続要求で使用される永続的な接続が残されますが、これは望ましくありません。
結局のところ、Secure Transport TLS セッション キャッシュが原因だと思います。
また、Apple Developer Forumsで質問したところ、Apple の担当者から回答がありました。彼は、次のApple サンプル コードの readmeを教えてくれました。
iOS と Mac OS X の両方で TLS スタックの一番下にあるのは、セキュア トランスポートと呼ばれるコンポーネントです。Secure Transport は、プロセスごとの TLS セッション キャッシュを維持します。TLS 経由で接続すると、TLS ネゴシエーションに関する情報がキャッシュに保存されるため、後続の接続がより迅速に接続できるようになります。オンザワイヤのメカニズムについては、以下のリンクで説明されています。
http://en.wikipedia.org/wiki/Transport_Layer_Security#Resumed_TLS_handshake
これは、特にデバッグ中に、いくつかの興味深い落とし穴を提示します。たとえば、次のシーケンスを考えてみましょう。
[Debug] タブを使用して、TLS Server Validation を [Disabled] に設定します。
自己署名 ID を使用してサイトに接続します。TLS サーバーの信頼検証を無効にしたため、接続は成功します。これにより、Secure Transport TLS セッション キャッシュにエントリが追加されます。
[Debug] タブを使用して、TLS Server Validation を [Default] に設定します。
手順 2 で行ったのと同じサイトにすぐに接続します。これは、サーバー信頼検証ポリシーの変更により失敗するはずですが、NSURLAuthenticationMethodServerTrust チャレンジを受信しないため成功します。内部では、セキュア トランスポートが TLS セッションを再開しました。
一方、ステップ 3 と 4 の間で 11 分間遅延すると、期待どおりに動作します (まあ、期待どおりに失敗します :-)。これは、Secure Transport の TLS セッション キャッシュのタイムアウトが 10 分であるためです。
現実の世界では、これは大きな問題ではありませんが、デバッグ中に非常に混乱する可能性があります。Secure Transport TLS セッション キャッシュをプログラムでクリアする方法はありませんが、キャッシュはプロセスごとであるため、アプリケーションを終了して再起動するだけで、デバッグ中にこの問題を回避できます。iOS 4 以降では、ホーム ボタンを押しても必ずしもアプリケーションが終了するとは限らないことに注意してください。代わりに、最近のアプリケーション リストからアプリケーションを終了する必要があります。
そのため、ユーザーはアプリを強制終了して再起動するか、10 分以上待ってから別のリクエストを送信する必要があります。
この新しい情報で別の Google 検索を行ったところ、この問題と完全に一致する Apple の技術的な Q&A 記事が見つかりました。下部近くに、末尾に「.」を追加することが記載されています。TLSセッションキャッシュミスを強制するためにリクエストのドメイン名(およびできればIPアドレス)に(サーバーを何らかの方法で変更できない場合、私にはできません)、これを試してみます。動作します。私はそれをテストした後、私の発見を投稿します。
### 編集 ###
「。」を追加してテストしました IP アドレスの末尾に追加しても、リクエストは正常に完了しました。
しかし、私は一般的な問題について考えていましたが、別の SSL ハンドシェイクを強制する理由は本当にありません。私の場合、この問題の解決策は、サーバーから返された最後の既知の SecCertificateRef のコピーを保持することです。サーバーに別のリクエストを行うときに、キャッシュされた TLS セッションが使用されている (呼び出されていない) 場合、保存されたセッションがまだ有効connection:didReceiveAuthenticationChallenge:
であることがわかります。が呼び出されたSecCertificateRef
場合、その時点で new を取得できます。connection:didReceiveAuthenticationChallenge:
SecCertificateRef
まず、[self.conn cancel]を使用する必要があります。次に、それが言うとおりに実行します。キャンセルします。その後NSURLConnectionを使用したくない場合は、何も実行されません。再度使用する場合は、別のリクエストを設定するだけで、特定のサーバーに接続できます。
お役に立てば幸いです。