私は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#リクエストと共に証明書と公開鍵/秘密鍵を提供するにはどうすればよいですか。
サーバが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);
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(またはそれ以下)を実行している場合は、選択する必要があります
あなたのコードはこのように修正されるべきです:
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();
ユーザーエージェントが必要な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");
https
に接続するとき、私もこのエラーを得ました、私はHttpClient httpClient = new HttpClient();
の前にこの行を追加して、首尾よく接続します:
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
私はそれを知っている この答え と もう一つの類似Anwser とコメントの言及:
これは開発に役立つハックなので、#if DEBUG #endifステートメントをその周りに置くことは、これをより安全にして本番で終わることを止めるために最低限必要なことです
その上、私は証明書を作るためにnew X509Certificate()
またはnew X509Certificate2()
を使う もう一つの答え でメソッドを試していません、私は単にnew()
によって作成されたものがうまくいくかどうかわからない。
編集:いくつかの参考文献:
ServerCertificateValidationCallbackを使用するためのベストプラクティス
Thumbprintの値がx509certificate.GetCertHashString()
と等しいことがわかりました。
URIにHTTPSを指定するだけでうまくいきます。
httpClient.BaseAddress = new Uri("https://foobar.com/");
リクエストがHTTPで機能するがHTTPSで失敗する場合これは証明書の問題です。呼び出し側が証明書発行者を信頼していること、および証明書が期限切れになっていないことを確認してください。これを確認するための迅速で簡単な方法は、ブラウザでクエリを作成することです。
また、サーバーがHTTPS要求を正しく処理するように設定されていることを確認することもできます(自分のサーバーである場合、および/または可能な場合)。
私はまたエラーを受けていました:
基礎となる接続が閉じられました。SSL/ TLSセキュアチャネルの信頼関係を確立できませんでした。
...Xamarin Forms Android - TLS 1.3が必要なAPIプロバイダーからリソースをリクエストしようとしているターゲットアプリケーション
解決策は、Xamarinの "管理"(.NET)httpクライアント(Xamarin Forms v2.5の時点ではTLS 1.3をサポートしていません)を交換し、代わりにAndroidネイティブクライアントを使用するようにプロジェクト設定を更新することでした。
これはビジュアルスタジオで簡単に切り替えられるプロジェクトです。下のスクリーンショットを見てください。
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を確認)。
以下の宣言をクラスに追加してください。
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;
ハッピー? :)
ModernHttpClientNugetパッケージを使用して試すことができます。パッケージをダウンロードしたら、次のように実装できます。
var handler = new ModernHttpClient.NativeMessageHandler()
{
UseProxy = true,
};
handler.ClientCertificateOptions = ClientCertificateOption.Automatic;
handler.PreAuthenticate = true;
HttpClient client = new HttpClient(handler);
私は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