Httpsリソースを要求するときに証明書チェックを無視する方法を見つけようとしています。これまでのところ、インターネットで役に立つ記事を見つけました。
しかし、私はまだいくつか問題があります。私のコードを見直してください。 ServicePointManager.ServerCertificateValidationCallback
というコードの意味が理解できないのですが。
このデリゲートメソッドはいつ呼び出されますか?もう1つ質問があります。このコードはどこで作成しますか。 ServicePointManager.ServerCertificateValidationCallback
を実行する前、またはStream stream = request.GetRequestStream()
を実行する前に
public HttpWebRequest GetRequest()
{
CookieContainer cookieContainer = new CookieContainer();
// Create a request to the server
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_remoteUrl);
#region Set request parameters
request.Method = _context.Request.HttpMethod;
request.UserAgent = _context.Request.UserAgent;
request.KeepAlive = true;
request.CookieContainer = cookieContainer;
request.PreAuthenticate = true;
request.AllowAutoRedirect = false;
#endregion
// For POST, write the post data extracted from the incoming request
if (request.Method == "POST")
{
Stream clientStream = _context.Request.InputStream;
request.ContentType = _context.Request.ContentType;
request.ContentLength = clientStream.Length;
ServicePointManager.ServerCertificateValidationCallback = delegate(
Object obj, X509Certificate certificate, X509Chain chain,
SslPolicyErrors errors)
{
return (true);
};
Stream stream = request.GetRequestStream();
....
}
....
return request;
}
}
1つのグローバル ServicePointManager しかないため、 ServicePointManager.ServerCertificateValidationCallback と設定すると、後続のすべての要求がこのポリシーを継承するという結果になります。これはグローバルな「設定」なので、 Global.asax の Application_Start メソッドで設定することをお勧めします。
コールバックを設定すると、デフォルトの動作が無効になり、独自の検証ルーチンを自分で作成できます。
リクエストごとにこのソリューションを適用することに興味がある人のために、これはオプションであり、ラムダ式を使用します。 blak3rで言及されているグローバルフィルタにも同じラムダ式を適用できます。この方法は.NET 4.5を必要とするようです。
String url = "https://www.stackoverflow.com";
HttpWebRequest request = HttpWebRequest.CreateHttp(url);
request.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
.NET 4.0では、ラムダ式はグローバルフィルタにそのまま適用できます。
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
これは私のために働いた:
System.Net.ServicePointManager.ServerCertificateValidationCallback +=
delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate,
System.Security.Cryptography.X509Certificates.X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
return true; // **** Always accept
};
ここからの抜粋: http://www.west-wind.com/weblog/posts/2011/Feb/11/HttpWebRequest-and-Ignoring-SSL-Certificate-Errors
短いデリゲートソリューションもあります:
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
.NET 4.5より前のバージョンでは、そのServicePointManager
にアクセスする要求のプロパティは利用できませんでした。
これが、要求ごとにServicePoint
にアクセスするための.NET 4.0コードです。リクエストごとのコールバックにアクセスすることはできませんが、問題の詳細を知ることができるはずです。 scvPoint.Certificate
(または望むならClientCertificate
)プロパティにアクセスするだけです。
WebRequest request = WebRequest.Create(uri);
// oddity: these two .Address values are not necessarily the same!
// The service point appears to be related to the .Host, not the Uri itself.
// So, check the .Host vlaues before fussing in the debugger.
//
ServicePoint svcPoint = ServicePointManager.FindServicePoint(uri);
if (null != svcPoint)
{
if (!request.RequestUri.Host.Equals(svcPoint.Address.Host, StringComparison.OrdinalIgnoreCase))
{
Debug.WriteLine(".Address == " + request.RequestUri.ToString());
Debug.WriteLine(".ServicePoint.Address == " + svcPoint.Address.ToString());
}
Debug.WriteLine(".IssuerName == " + svcPoint.Certificate.GetIssuerName());
}
偶然にも、これは私が知っている特定のアプリですべての証明書の検証をオフにする最も冗長な方法です。
ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;
Adamの答えとRobのコメントに基づいて、私はこれを使いました:
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => certificate.Issuer == "CN=localhost";
これは「無視する」ことをややフィルタリングします。もちろん必要に応じて他の発行者を追加することができます。我々はいくつかのレガシーコードをサポートする必要があるので、これは.NET 2.0でテストされました。
グローバルに証明書検証をオーバーライドするServicePointManagerにコールバックを追加するのではなく、HttpClientのローカルインスタンスにコールバックを設定できます。この方法は、そのHttpClientのインスタンスを使用して行われた呼び出しにのみ影響するはずです。
以下は、特定のサーバーに対する証明書検証エラーの無視をWeb APIコントローラーに実装する方法を示すサンプルコードです。
using System.Net.Http;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
public class MyController : ApiController
{
// use this HttpClient instance when making calls that need cert errors suppressed
private static readonly HttpClient httpClient;
static MyController()
{
// create a separate handler for use in this controller
var handler = new HttpClientHandler();
// add a custom certificate validation callback to the handler
handler.ServerCertificateCustomValidationCallback = ((sender, cert, chain, errors) => ValidateCert(sender, cert, chain, errors));
// create an HttpClient that will use the handler
httpClient = new HttpClient(handler);
}
protected static ValidateCert(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors errors)
{
// set a list of servers for which cert validation errors will be ignored
var overrideCerts = new string[]
{
"myproblemserver",
"someotherserver",
"localhost"
};
// if the server is in the override list, then ignore any validation errors
var serverName = cert.Subject.ToLower();
if (overrideCerts.Any(overrideName => serverName.Contains(overrideName))) return true;
// otherwise use the standard validation results
return errors == SslPolicyErrors.None;
}
}
明示的に表現しています...
ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(CertCheck);
private static bool CertCheck(object sender, X509Certificate cert,
X509Chain chain, System.Net.Security.SslPolicyErrors error)
{
return true;
}
CA5386:脆弱性分析ツールは、これらのコードについて警告します。
正しいコード:
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) =>
{
return (sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != SslPolicyErrors.RemoteCertificateNotAvailable;
};
ヒント:この方法を使用して、もうすぐ期限切れになる証明書を追跡することもできます。期限切れになる証明書を発見し、それを期限内に修正できる場合は、これでベーコンを節約できます。サードパーティ企業にも良い - 私たちにとってこれはDHL /フェデックスです。 DHLは、感謝祭の3日前に証明書を失効させます。幸いなことにそれを修正しようとしています...今回は!
private static DateTime? _nextCertWarning;
private static bool ValidateRemoteCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error)
{
if (error == SslPolicyErrors.None)
{
var cert2 = cert as X509Certificate2;
if (cert2 != null)
{
// If cert expires within 2 days send an alert every 2 hours
if (cert2.NotAfter.AddDays(-2) < DateTime.Now)
{
if (_nextCertWarning == null || _nextCertWarning < DateTime.Now)
{
_nextCertWarning = DateTime.Now.AddHours(2);
ProwlUtil.StepReached("CERT EXPIRING WITHIN 2 DAYS " + cert, cert.GetCertHashString()); // this is my own function
}
}
}
return true;
}
else
{
switch (cert.GetCertHashString())
{
// Machine certs - SELF SIGNED
case "066CF9CAD814DE2097D367F22D3A7E398B87C4D6":
return true;
default:
ProwlUtil.StepReached("UNTRUSTED CERT " + cert, cert.GetCertHashString());
return false;
}
}
}
上記のいくつかの答え。私は、コードを変更し続ける必要がなく、コードを安全でないものにしないアプローチを望んでいました。そこで私はホワイトリストを作りました。ホワイトリストはどのデータストアでも管理できます。非常に小さいリストなので、設定ファイルを使用しました。
私のコードは以下の通りです。
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, error) => {
return error == System.Net.Security.SslPolicyErrors.None || certificateWhitelist.Contains(cert.GetCertHashString());
};
Saniとblak3rの答えに加えて、私は自分のアプリケーションのスタートアップコードに以下を追加しましたが、VBでは:
'** Overriding the certificate validation check.
Net.ServicePointManager.ServerCertificateValidationCallback = Function(sender, certificate, chain, sslPolicyErrors) True
トリックをするようだ。