• 企业自颁布服务器证书的有效性验证(C#为例)


    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/notjusttech/article/details/72779904

    目前根据项目的需要,整理了一下公司内部的安全通信规范,将其中涉及证书验证的部分分享出来,供探讨。

    处于通信安全的考虑,很多通过互联网进行的通信,

    原则上均要求使用加密通信,即采用基于SSL或TLS的安全通信。对于Web应用及Web API来说,原则上应该一律使用HTTPS,禁用HTTP;对于Socket通信来说,原则上应采用SSL协议加密传输。

    基于SSL协议,需要服务器证书。对于Web应用及Web API(统称站点),原则上应使用由全球可信机构颁发的证书。但是考虑到证书费用、站点条件等一些因素,对于下列情形,可考虑使用自颁发证书:

    1.      站点只在特定局域网、专网内部署使用;

    2.      站点只有IP地址,没有注册域名;

    3.      站点所有者不愿意支付证书费用。

    若考虑企业自己建个证书颁发机构(CA),那就涉及到客户端对服务器证书的验证问题。目前很多人提到的做法都是实现自定义验证,但所谓的自定义验证就是直接返回true。这样处理,虽然能进行HTTPS加密通信,但由于实际上未对服务器证书做任何验证,因此是存在中间人攻击风险的。

    本人研究了一下这个问题,发现针对.net开发,在中文网站上似乎没有很好的实现建议,因此才想到整理这篇博文和大家分享我们的做法,欢迎各位大拿批评指正。

    首先,要使用自颁发证书实现HTTPS通信,最好是要对企业自己的CA做一个统一管理,CA必须具有唯一性,并且CA一旦建立,原则上应保证永不更改,从而保证企业CA的权威性。CA的权威性,是通信过程中对服务器证书进行可信验证、防止中间人攻击的基础。

    其次,对自颁发证书的申请与获取,也要遵循一定的原则,主要是证书的使用者要和实际站点IP地址或域名一致,另外根据需要考虑证书有效期问题。

    最后,就是在客户端对服务器证书的有效性验证了。我们将这个问题分为两部分:

    (一)Web应用(网站)

    对于Web应用来说,都是通过浏览器访问,而浏览器对证书的验证过程我们是无法干预的。对于自颁发证书,浏览器会提示证书无效。对于这个问题,我们的做法是参考铁总12306网站的做法:

    将我们的CA证书即根证书(公钥)文件通过某种途径,发送给所有用户,要求用户将根证书安装到“受信任的根证书颁发机构”。从而防止中间人攻击。

    (二)Web API

    Web API均为某种客户端程序调用,调用接口需做业务权限验证。因此对于证书的验证,是在自研程序中执行。

    对于自颁发证书,各研发平台的默认验证肯定是不通过的,有两种方式:

    1、             跟Web网站一样,要求所有客户端设备(电脑、终端设备)均将我们的根证书安装到可信证书区域,从而可使用默认的验证方式,代码不用做任何额外处理。但这种方式,会有一定局限性,很多时候不大可行。

    2、             将根证书集成到项目中,通过代码实现自定义验证。自定义验证项目包括:

    a)        构建证书链,看服务器证书是否能链接到我们的根证书;这里对于不同的开发语言,处理可能不同。在C#中,需要将我们的根证书放到链引擎可搜索到的地方,然后设置合适的链策略,再重新构建证书链。

    b)        上述验证通过后,验证服务器证书的使用者是否就是当前请求Uri的主机地址(IP或域名),是则通过验证;否则就是A地址的证书,用在了B地址的网站上。

    服务器证书的有效期可以不用验证。由于默认的有效期是1年,如果验证有效期的话,则服务器证书每年都要更新,对于自颁发证书,没有这个必要,就让它永远有效。

    如果客户端是C#,可以按如下方式进行验证

    根据项目情况做一些初始化,比如初始化根证书等。

     1 static String caFilePath = "D:\…….cer"; //本地根证书路径
     2 static X509Certificate2 ca; //本地根证书对象
     3 
     4 //验证代码一
     5 WebRequestHandler wrh;
     6 wrh = new WebRequestHandler();
     7 wrh.ServerCertificateValidationCallback += RemoteCertificateValidate;
     8 //验证代码二 
     9 ServicePointManager.ServerCertificateValidationCallback = RemoteCertificateValidate;//验证服务器证书回调自动验证
    10 
    11 
    12 if (File.Exists(caFilePath))
    13 {
    14     ca = new X509Certificate2(caFilePath); 
    15 }

    使用该WebRequestHandler处理Https连接,以便实现自定义证书验证

    1 HttpClient client = new HttpClient(wrh);
    2 ……

    自定义验证的实现:

     1 private bool RemoteCertificateValidate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error)
     2 {
     3     if (null != ca)
     4     {
     5         /*
     6          * 根证书未安装到“受信任的根证书颁发机构”时,默认是无法形成可信证书链的。(chain中将只有服务器证书本身)
     7          * 需更改链策略,然后重新构建证书链。
     8         */
     9         // 将我们的根证书放到链引擎可搜索到的地方
    10         chain.ChainPolicy.ExtraStore.Add(ca);
    11         //不执行吊销检查
    12         chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
    13         //忽略CA未知情况、不做时间检查
    14         chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority | X509VerificationFlags.IgnoreNotTimeNested | X509VerificationFlags.IgnoreNotTimeValid;
    15         //重新构建可信证书链
    16         bool isOk = chain.Build(cert as X509Certificate2);
    17         if (isOk)
    18         {
    19             X509Certificate2 cacert = chain.ChainElements[chain.ChainElements.Count - 1].Certificate;  //获取最前面的证书,认为是根证书
    20             //与本地根证书比较
    21             if (ca.GetPublicKeyString().Equals(cacert.GetPublicKeyString()) && ca.Thumbprint.Equals(cacert.Thumbprint))
    22             {
    23                 HttpWebRequest req = sender as HttpWebRequest;
    24                 if (null != req && cert.Subject.Contains("CN=" + req.Address.Host))
    25                 {
    26                     return true;        //根证书可信且服务器证书确实是指定服务器的,验证通过
    27                 }
    28             }
    29         }
    30     }
    31     return false;
    32 }
    通过上述方式,可以灵活执行自定义的验证,比如既验证服务器证书确实是我们颁发给指定网站的,又可根据需要跳过证书有效性的验证。

    对于在java中做自定义验证,可参考一下博文(本人没仔细研究)

    http://pingguohe.net/2016/02/26/Android-App-secure-ssl.html

    --------------------- 本文来自 Darlzan 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/notjusttech/article/details/72779904
  • 相关阅读:
    两层和三层的讨论(C/S)
    FF IE 编码 转换
    MySql数据库 字符编码问题解决办法
    JDO的persistence by reachability
    技术贴
    Eclipse 快捷键总结
    记录一下: 火狐 IE 实现图片本地预览 demo
    一般jsp 翻页 选择 保留 代码
    复习下几个排序
    Eclipse 插件开发 资料贡献
  • 原文地址:https://www.cnblogs.com/guanshan/p/guan2018-9-27.html
Copyright © 2020-2023  润新知