web-dev-qa-db-ja.com

HttpClientを使用してHttpsを呼び出す

私はC#を使ってWebApiを呼び出すためにHttpClientを使っています。 WebClientと比較してきれいで速い方法のようです。しかし、私はHttps呼び出しをしている間立ち往生しています。

どのように私はHttps呼び出しをするために以下のコードを作ることができますか?

HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("https://foobar.com/");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(
                new MediaTypeWithQualityHeaderValue("application/xml"));

var task = httpClient.PostAsXmlAsync<DeviceRequest>(
                "api/SaveData", request);

編集1:上記のコードはhttp呼び出しを行うのに問題なく動作します。しかし、スキームをhttpsに変更してもうまくいきません。得られるエラーはここにあります:

基礎となる接続が閉じられました。SSL/ TLSセキュアチャネルの信頼関係を確立できませんでした。

編集2:スキームをhttpsに変更することはステップ1です。

C#リクエストと共に証明書と公開鍵/秘密鍵を提供するにはどうすればよいですか。

128
Abhijeet

サーバがTLS 1.2のみのようなより高いTLSバージョンのみをサポートする場合、クライアントPCがデフォルトでより高いTLSバージョンを使用するように設定されていない限り、それはまだ失敗します。この問題を解決するには、コードに次の行を追加してください。

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

サンプルコードを変更すると、

HttpClient httpClient = new HttpClient();   

//specify to use TLS 1.2 as default connection
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

httpClient.BaseAddress = new Uri("https://foobar.com/");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));

var task = httpClient.PostAsXmlAsync<DeviceRequest>("api/SaveData", request);
154
Ronald Ramos

URIにHTTPSを指定するだけです。

new Uri("https://foobar.com/");

Foobar.comは信頼できるSSL証明書を持っている必要があるでしょう、そうでなければあなたの電話は信頼できないエラーで失敗するでしょう。

編集回答: HttpClientを使用したClientCertificates

WebRequestHandler handler = new WebRequestHandler();
X509Certificate2 certificate = GetMyX509Certificate();
handler.ClientCertificates.Add(certificate);
HttpClient client = new HttpClient(handler);

編集回答2:接続しているサーバーがSSL、TLS 1.0、および1.1を無効にしていて、まだ.NET Framework 4.5(またはそれ以下)を実行している場合は、選択する必要があります

  1. .Net 4.6+にアップグレードする( デフォルトでTLS 1.2をサポートしています
  2. 4.5にTLS1.2を介して接続するよう指示するレジストリの変更を追加します(compatと変更するキーについては salesforce writeup を参照してくださいOR checkout IISCrypto Ronald Ramos コメントに答える )を参照
  3. TLS1.2を介して接続するように.NETを手動で設定するためのアプリケーションコードを追加します(Ronald Ramos answer を参照)。
121
felickz

あなたのコードはこのように修正されるべきです:

httpClient.BaseAddress = new Uri("https://foobar.com/");

あなただけのhttps: URIスキームを使用する必要があります。安全なHTTP接続についてのMSDNの有用なページ がここ にあります。確かに:

Https:URIスキームを使う

HTTPプロトコルは2つのURIスキームを定義します。

http:暗号化されていない接続に使用されます。

https:暗号化する必要がある安全な接続に使用されます。このオプションでは、デジタル証明書と認証局を使用して、サーバーが本物かどうかを確認します。

さらに、HTTPS接続はSSL証明書を使用することを検討してください。安全な接続にこの証明書があることを確認してください。そうしないと、要求は失敗します。

編集:

上記のコードはHTTP呼び出しを行うためにはうまく機能します。しかし、スキームをhttpsに変更しても機能しない場合は、エラーを投稿しましょう。

どういう意味ですか。要求は失敗しますか?例外がスローされますか?あなたの質問を明確にしてください。

要求が失敗した場合は、SSL証明書が問題になります。

この問題を解決するには、クラス HttpWebRequest を使用してから、そのプロパティClientCertificateを使用します。さらに、証明書を使用してHTTPS要求を行う方法に関する有用なサンプルが こちら にあります。

例は次のとおりです(前にリンクされたMSDNページに示されているように)。

//You must change the path to point to your .cer file location. 
X509Certificate Cert = X509Certificate.CreateFromCertFile("C:\\mycert.cer");
// Handle any certificate errors on the certificate from the server.
ServicePointManager.CertificatePolicy = new CertPolicy();
// You must change the URL to point to your Web server.
HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("https://YourServer/sample.asp");
Request.ClientCertificates.Add(Cert);
Request.UserAgent = "Client Cert Sample";
Request.Method = "GET";
HttpWebResponse Response = (HttpWebResponse)Request.GetResponse();
13
Alberto Solano

ユーザーエージェントが必要なGitHubに接続するときにも同じ問題がありました。したがって、証明書を生成するのではなくこれを提供するだけで十分です。

var client = new HttpClient();

client.BaseAddress = new Uri("https://api.github.com");
client.DefaultRequestHeaders.Add(
    "Authorization",
    "token 123456789307d8c1d138ddb0848ede028ed30567");
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add(
    "User-Agent",
    "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36");
6
Carlo V. Dango

httpsに接続するとき、私もこのエラーを得ました、私はHttpClient httpClient = new HttpClient();の前にこの行を追加して、首尾よく接続します:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

私はそれを知っている この答えもう一つの類似Anwser とコメントの言及:

これは開発に役立つハックなので、#if DEBUG #endifステートメントをその周りに置くことは、これをより安全にして本番で終わることを止めるために最低限必要なことです

その上、私は証明書を作るためにnew X509Certificate()またはnew X509Certificate2()を使う もう一つの答え でメソッドを試していません、私は単にnew()によって作成されたものがうまくいくかどうかわからない。

編集:いくつかの参考文献:

IIS 7に自己署名入りサーバー証明書を作成します

IIS 7にSSL証明書をインポートおよびエクスポートする

.pfxを.cerに変換します

ServerCertificateValidationCallbackを使用するためのベストプラクティス

Thumbprintの値がx509certificate.GetCertHashString()と等しいことがわかりました。

証明書の拇印を取得する

5
yu yang Jian

URIにHTTPSを指定するだけでうまくいきます。

httpClient.BaseAddress = new Uri("https://foobar.com/");

リクエストがHTTPで機能するがHTTPSで失敗する場合これは証明書の問題です。呼び出し側が証明書発行者を信頼していること、および証明書が期限切れになっていないことを確認してください。これを確認するための迅速で簡単な方法は、ブラウザでクエリを作成することです。

また、サーバーがHTTPS要求を正しく処理するように設定されていることを確認することもできます(自分のサーバーである場合、および/または可能な場合)。

3
Crono

私はまたエラーを受けていました:

基礎となる接続が閉じられました。SSL/ TLSセキュアチャネルの信頼関係を確立できませんでした。

...Xamarin Forms Android - TLS 1.3が必要なAPIプロバイダーからリソースをリクエストしようとしているターゲットアプリケーション

解決策は、Xamarinの "管理"(.NET)httpクライアント(Xamarin Forms v2.5の時点ではTLS 1.3をサポートしていません)を交換し、代わりにAndroidネイティブクライアントを使用するようにプロジェクト設定を更新することでした。

これはビジュアルスタジオで簡単に切り替えられるプロジェクトです。下のスクリーンショットを見てください。

  • プロジェクトプロパティ
  • Androidのオプション
  • 高度な
  • リスト項目
  • 「HttpClientの実装」を「Android」に変更
  • SSL/TLSの実装を "Native TLS 1.2+"に変更

enter image description here

1
MSC

HttpClientHandlerのレベルには非グローバル設定があります。

var handler = new HttpClientHandler()
{
    SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls
};

var client = new HttpClient(handler);

したがって、最新のTLSバージョンを有効にします。

デフォルト値SslProtocols.Defaultは実際にはSslProtocols.Ssl3 | SslProtocols.Tlsであることに注意してください(.Net Core 2.1および.Net Framework 4.7.1を確認)。

0
stop-cran

以下の宣言をクラスに追加してください。

public const SslProtocols _Tls12 = (SslProtocols)0x00000C00;
public const SecurityProtocolType Tls12 = (SecurityProtocolType)_Tls12;

後:

var client = new HttpClient();

そして:

ServicePointManager.SecurityProtocol = Tls12;
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 /*| SecurityProtocolType.Tls */| Tls12;

ハッピー? :)

0
Greg Stawski

ModernHttpClientNugetパッケージを使用して試すことができます。パッケージをダウンロードしたら、次のように実装できます。

 var handler = new ModernHttpClient.NativeMessageHandler()
 {
     UseProxy = true,
 };


 handler.ClientCertificateOptions = ClientCertificateOption.Automatic;
 handler.PreAuthenticate = true;
 HttpClient client = new HttpClient(handler);
0
Uchenna Nnodim

私はfelickzに同意しますが、c#での使用法を明確にするための例を追加したいと思います。次のようにWindowsサービスでSSLを使用します。

    var certificatePath = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "bin");
    gateway = new GatewayService();
    gateway.PreAuthenticate = true;


    X509Certificate2 cert = new X509Certificate2(certificatePath + @"\Attached\my_certificate.pfx","certificate_password");
    gateway.ClientCertificates.Add(cert);

    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
    gateway.UserAgent = Guid.NewGuid().ToString();
    gateway.Timeout = int.MaxValue;

Webアプリケーションで使用する場合は、プロキシ側の実装を次のように変更するだけです。

public partial class GatewayService : System.Web.Services.Protocols.SoapHttpClientProtocol // to => Microsoft.Web.Services2.WebServicesClientProtocol
0
Hamit YILDIRIM