web-dev-qa-db-ja.com

このHTTPSWebRequestがブラウザーで機能しているのに、何がタイムアウトするのですか?

これが私のリクエストです:

var request = (HttpWebRequest) WebRequest.Create("https://mtgox.com/");
request.CookieContainer = new CookieContainer();
request.AllowAutoRedirect = false;
request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
request.Headers[HttpRequestHeader.AcceptEncoding] = "gzip, deflate";
request.Headers[HttpRequestHeader.AcceptLanguage] = "en-gb,en;q=0.5";
request.Headers[HttpRequestHeader.AcceptCharset] = "ISO-8859-1,utf-8;q=0.7,*;q=0.7";
request.Timeout = 5000;
request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0";
request.Method = "GET";

request.GetResponse();

ヘッダーは、HttpFoxを使用してFirefoxからコピーされました。 Fiddler2を使用して、少なくともHTTPリクエストの場合、ヘッダーがFirefoxリクエストと私のリクエストの間で完全に同一であることを確認しました。

ただし、HTTPSを使用してこの特定のWebサイトにリクエストを実行すると、リクエストは単にタイムアウトします。他のウェブサイトでも機能します。

Firefoxで常に機能するため、Firefoxとは異なる方法で実行する必要があります。ただし、Fiddler2を使用してデバッグすることはできません。これは、Fiddler2がこれらの要求を転送するたびに、Firefoxによって発信された場合でも、それらの要求がタイムアウトになるためです。

それは本当にバグのあるウェブサイトですか?上記のどの部分がFirefoxではないと私に教えてくれますか?

19
enverpex

Microsoft Network Monitorを使用して、HttpWebRequestがクライアントの鍵交換を送り返すことになっている段階でスタックすることがわかりました。それは単にしませんでした。サーバーはそれを適切に待っていましたが、それは実現しませんでした。

HttpWebRequestがTLSの代わりにSSL3を使用することを強制していた問題を修正しました(TLSは必要に応じて自動的にSSL3に変わるはずですが):

ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;

なぜそうなのか、私にはわからないと思います-私が知っている誰よりも理解するのに時間がかかる不思議なことの1つにすぎません...

キャプチャに関して異なる点の1つは、TLSバリアント Server Hello応答に「アラート」エントリがありました です。これはSSL3交換にも、実際に機能したすべてのTLS交換にも存在しません。ただし、不思議なことに、リクエストを正常に実行しているFirefoxのキャプチャにも同じアラートが表示されます。

最後に、この質問を最初に投稿したときに一時的なOCSPの不具合が発生したようですが、その後解決されました。これは混乱を助長しましたが、主要な問題ではありません。

43
enverpex

HttpWebRequest/HttpWebReponse呼び出しでタイムアウトエラーが発生する一般的な理由は、接続をアクティブに保つ「応答オブジェクト/ストリームを閉じない」ことです。ストリームの内容を読み取った後、StreamオブジェクトまたはHttpWebResponseオブジェクトを閉じる必要があります。デフォルトの接続制限は2です。

HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
Stream stream = webResponse.GetResponseStream();
string responseString = ((TextReader)new StreamReader(stream)).ReadToEnd();
webResponse.Close();

または、多くのユーザーが同時に呼び出すWebサービスにロジックを実装した場合は、HttpWebRequestオブジェクトの接続制限を増やすことを検討してください。

HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(url);    
webRequest.ServicePoint.ConnectionLimit = 20;
11
Prabu Arumugam

Windows 7の.NETFrameworkは、TLS拡張機能であるServer Name Indication(RFC4366)を実装しています。あなたの投稿によると このTLSアラートはどういう意味ですか サーバーは「認識されない名前」で応答しています。実際にはタイムアウトしないため、接続がタイムアウトすると報告される理由がわかりません。ネットワークトレースは、この[FIN、ACK]の後にクライアントが接続の終了を開始したことを示しているはずです。 SSL3にダウングレードすると、SNIの呼び出しが回避されます。

参考:Windows上の同じ.NETフレームワークXPはTLSServer Name IndicationExtensionを使用しません。プログラムはそこで動作します..。

私の場合、これの発生をApacheで欠落しているServerNameディレクティブにトレースしました。 ServerNameをSSL構成に追加すると、Webサーバーがその名前を認識しなくなったため、問題が解決しました。

9
dotwilbert

最近、この同じ問題について知り、Microsoftが新しい.netバージョンでこれを修正した可能性があるかどうかを確認したいと思いました。これは私がテストしたコードです(プライバシーのためにドメインが削除されました):

HttpWebRequest request =
    (HttpWebRequest)WebRequest.Create("https://www.xxSomeDomainNamexx.com/");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
Console.WriteLine(reader.ReadToEnd());

これを.netバージョン2.0、3.0、および3.5に対してコンパイルすると、すべてここで議論されているのとまったく同じ動作を示すように見えました。次に、4.0と4.5に対してコンパイルを試み、両方の場所で適切な応答を受け取りました。

これに基づいて、Microsoftは新しい.netバージョンでこの問題を修正した可能性が高いようです。後世のために、enverpexによって提案されたSecurityProtocolの変更もテストしました。これは、2.0、3.0、および3.5でうまく機能しました。

4
Trite

Httpsリクエストでも同じタイムアウトの問題が発生しましたが、どの回答も役に立ちませんでした。ちょうど今、私は自分の問題を解決する解決策を見つけました。これは、.net Framework4.5以降でのみ機能することに注意してください。

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
var response = WebRequest.Create("https://yoursecurewebservice").GetResponse();
var body = new StreamReader(response.GetResponseStream()).ReadToEnd();
Console.WriteLine(body);
3
henon

ルート証明書がない、またはOCSPレスポンダーにアクセスできないなどの理由で、HTTPSクライアントがこのサーバーによって提示された証明書チェーンを検証できない可能性があります。つまりブラウザと使用するHTTPSクライアントで異なる設定が行われる可能性があります。

オプションの1つとして、 HTTPBlackbox コンポーネントの試用版を入手し、TElHTTPSClientを使用して接続を試みることができます。それはあなたに詳細なエラー情報(エラーの場合)を与えるので、あなたはHttpWebRequestの何が悪いのかを判断することができます。