我正在尝试连接到使用自签名SSL证书的API.我这样做是使用.NET的HttpWebRequest和HttpWebResponse对象.我得到一个例外:
底层连接已关闭:无法为SSL/TLS安全通道建立信任关系.
我明白这意味着什么.我理解为什么 .NET认为它应该警告我并关闭连接.但在这种情况下,无论如何我都想连接到API,中间人攻击会被诅咒.
那么,我该如何为这个自签名证书添加例外呢?或者是告诉HttpWebRequest/Response不要验证证书的方法?我该怎么办?
事实证明,如果您只想完全禁用证书验证,则可以更改ServicePointManager上的ServerCertificateValidationCallback,如下所示:
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
这将验证所有证书(包括无效,过期或自签名证书).
@Domster:这有效,但您可能希望通过检查证书哈希是否符合您的预期来强制执行一些安全性.所以扩展版看起来有点像这样(基于我们正在使用的一些实时代码):
static readonly byte[] apiCertHash = { 0xZZ, 0xYY, ....}; ////// Somewhere in your application's startup/init sequence... /// void InitPhase() { // Override automatic validation of SSL server certificates. ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertficate; } ////// Validates the SSL server certificate. /// /// An object that contains state information for this /// validation. /// The certificate used to authenticate the remote party. /// The chain of certificate authorities associated with the /// remote certificate. /// One or more errors associated with the remote /// certificate. ///Returns a boolean value that determines whether the specified /// certificate is accepted for authentication; true to accept or false to /// reject. private static bool ValidateServerCertficate( object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors sslPolicyErrors) { if (sslPolicyErrors == SslPolicyErrors.None) { // Good certificate. return true; } log.DebugFormat("SSL certificate error: {0}", sslPolicyErrors); bool certMatch = false; // Assume failure byte[] certHash = cert.GetCertHash(); if (certHash.Length == apiCertHash.Length) { certMatch = true; // Now assume success. for (int idx = 0; idx < certHash.Length; idx++) { if (certHash[idx] != apiCertHash[idx]) { certMatch = false; // No match break; } } } // Return true => allow unauthenticated server, // false => disallow unauthenticated server. return certMatch; }
请注意,在.NET 4.5中,您可以为每个HttpWebRequest本身覆盖SSL验证(而不是通过影响所有请求的全局委托):
http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.servercertificatevalidationcallback.aspx
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri); request.ServerCertificateValidationCallback = delegate { return true; };
将自签名证书添加到本地计算机受信任的根证书颁发机构
您可以通过以管理员身份运行MMC来导入证书.
如何:使用MMC管理单元查看证书
Domster的答案中使用的验证回调的范围可以限制为使用ServerCertificateValidationCallback
委托上的sender参数的特定请求.以下简单范围类使用此技术临时连接仅对给定请求对象执行的验证回调.
public class ServerCertificateValidationScope : IDisposable { private readonly RemoteCertificateValidationCallback _callback; public ServerCertificateValidationScope(object request, RemoteCertificateValidationCallback callback) { var previous = ServicePointManager.ServerCertificateValidationCallback; _callback = (sender, certificate, chain, errors) => { if (sender == request) { return callback(sender, certificate, chain, errors); } if (previous != null) { return previous(sender, certificate, chain, errors); } return errors == SslPolicyErrors.None; }; ServicePointManager.ServerCertificateValidationCallback += _callback; } public void Dispose() { ServicePointManager.ServerCertificateValidationCallback -= _callback; } }
上述类可用于忽略特定请求的所有证书错误,如下所示:
var request = WebRequest.Create(uri); using (new ServerCertificateValidationScope(request, delegate { return true; })) { request.GetResponse(); }