65.9K
CodeProject 正在变化。 阅读更多。
Home

SSL 对等验证

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (4投票s)

2011 年 4 月 21 日

CPOL

4分钟阅读

viewsIcon

52185

使用 CA 文件在客户端验证服务器证书

引言

当使用 HTTPS 和 SSL 调用 Web 服务时,主机验证和对等验证需要处理以保证安全。本文展示并解释了当通过SSL保护的HTTPS调用 Web 服务时,如何成功地进行对等验证

Using the Code

大多数 Web 服务托管在 HTTPS 上,并由 SSL 保护,因此其他人无法使用它。很多时候,当我们浏览一个 HTTPS 站点时,我们会收到一个证书对话框,要求我们信任该提供者。这是 Web 服务器发送的服务器证书。我们接受证书并继续前进。在桌面应用程序中,当我们执行类似的任务(例如访问使用 HTTPS 和 SSL 的 Web 服务)时,我们无法收到任何对话框来信任证书,问题就来了。

通过创建我们自己的实现 ICertificatePolicy 接口的 CertificatePolicy 类,可以轻松实现这一点。例如,这样的类可以写成

public class MyPolicy : ICertificatePolicy {

    public MyPolicy() {
    }

    public bool CheckValidationResult(ServicePoint srvPoint, 
                X509Certificate certificate, 
                WebRequest request, int certificateProblem)
    {
        // Perform operations to verify
        // the certificate and return true or false 
        return true;
    }
}

并且可以设置

ServerCertificateValidationonCallback = MyPolicy();

上面的代码也可以使用 System.Net.ServicePointManager.ServerCertificateValidationonCallback 的委托来编写。

System.Net.
ServicePointManager.ServerCertificateValidationCallback = {
     (Object sender, X509Certificate certificate, X509Chain chain, 
             SslPolicyErrors sslPolicyErrors) {
         return true;
     }
};

上面的代码接受服务器证书(在浏览器上弹出的信任提供者的对话框)。它隐式地返回 true,这意味着它接受任何服务器证书并继续访问 Web 服务。

这非常简单容易。但是,如果 SSL 专门用于安全和密码学,并且可以如此容易地绕过,那么 SSL 还有什么意义呢?什么都没有,对吧?

当我们的客户端对照任何证书文件验证此服务器证书时,即,没有验证验证证书来验证服务器证书,客户端无法访问来自提供者的任何 Web 服务。这就像提供密码或验证密码一样。如果没有实际验证,给出和接收数据的 Web 服务应该很容易伪造。因此,我们需要使用“正确”版本的验证证书 *来验证服务器证书。验证证书只是一个 CA 文件,它比较服务器证书的数据。如果两者匹配,则返回 true 并允许我们访问 Web 服务,否则返回 false 并且不允许我们访问 Web 服务及其机密数据。

注意*:用于验证的证书与客户端证书不同,两者不同,它们的角色也不同。如果服务器需要客户端证书,则将客户端证书传递给服务器。可以使用 request.ClientCertificates 属性进行设置。

现在重点来了:我们如何验证服务器证书是否正确,或者服务器证书是否与验证证书匹配?虚假用户可以更改服务器证书或用于验证的证书,因此我们必须注意双方。

以下代码可帮助您接受服务器证书,并根据 CA 文件验证证书。

记住:接受服务器证书的代码应该只在整个应用程序生命周期中设置一次。并且每当发出请求时都会自动调用它。因此,为了便于编码,我们将把 SSL 证书部分与请求部分分开。

以下是设置和处理 SSL 证书部分的代码

// Certificate to verify 
private X509Certificate2 verifyCert = null;   

private void setSSLCertificate() {
     veriftCert = new X509Certificate2("ca_verify.crt");
     ServicePointManager.ServerCertificateValidationCallback += new 
       System.Net.Security.RemoteCertificateValidationCallback(
       customCertificateValidation);
}

public bool customCertificateValidation(Object sender, 
       X509Certificate certificate, X509Chain chain, 
       SslPolicyErrors sslPolicyErrors) 
{
      switch(sslPolicyErrors) {
           case RemoteCertificateChainErrors:
           case RemoteCertificateNameMismatch:
           case RemoteCertificateNotAvailable:
                   break;
      }
      // With this we have accepted the server certificate
      // Now, VERIFY the certificate against verifyCert
      // If details of both the certificates matches, then returns true, else false 
      return verifyCert.Verify();   
}

就这样。这就是处理对等验证的方式,并且应该注意,不要进行任何硬编码或在代码中进行比较。

现在,每当执行任何请求时,将首先调用 customCertificateValidation(),如果该函数返回 true,则请求将能够继续,否则将捕获 WebException

private void SendPost(String post_data) {

     HttpWebRequest request = (HttpWebRequest)WebRequest.Create(
       <a href="https://ae-q01.com/">https://ae-q01.com/</a>);
     request.KeepAlive = true;
     request.ContentType = "application/x-www-form-urlencoded";
     request.Method = "POST";
     byte[] postBytes = Encoding.ASCII.GetBytes(psot_data);
     Stream requestStream = null;

     try {
           // Send
           request.ContentLength = postBytes.Length;
           requestStream = request.GetRequestStream();
           requestStream.Write(postBytes, 0, postBytes.Length);
     } catch (WebException we) {

     // If our customCertificateValidation returns false, here it will be caught. 
     // You can check the status of WebException we.Status,
     // mostly it returns TrustFailure and handle them
     } catch(Exception e) {
          // Handle other normal request errors
     } finally {
          if (requestStream != null)
              requestStream.Close();  
     }
}

不要忘记在应用程序启动时或在调用任何 Web 服务之前适当的时间调用 setSSLCertificate()

这就是 SSL 对等验证的全部内容。我确信这肯定会帮助更多的开发人员实际交叉检查 SSL 验证,而不仅仅是盲目地接受服务器证书。

请告诉我它是否有效。

关注点

我想执行 SSL 对等验证。我在 Google 上搜索并在论坛中问了很多问题,但只能找到如何接受服务器证书,而不是如何验证它,这在您访问实现 SSL 安全性的 Web 服务时是最重要的。最后,当我找到解决方案时,我想与所有人分享,以使其他人的工作更容易一些。

历史

这是我在 CodeProject 上的第一篇文章。如果我犯了任何错误,请告知我; 欢迎任何改进建议。

© . All rights reserved.