2017-10-16 83 views
1

我的软件使用HTTPS连接连接到Dropbox以检索一些敏感数据。C#.NET - 固定证书颁发机构 - 我做的正确吗?

我想固定证书颁发机构以防止中间人攻击。

到目前为止,我有以下代码:

static bool VerifyServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) 
{ 
     try 
     { 
      var currentCaPublicKey = chain.ChainElements.Cast<X509ChainElement>().Last().Certificate.GetPublicKeyString(); 

      var caPublicKeys = new List<string>(){"00ad0e15cee443805cb187f3b760f97112a5aedc269488aaf4cef520392858600cf880daa9159532613cb5b128848a8adc9f0a0c83177a8f90ac8ae779535c31842af60f98323676ccdedd3ca8a2ef6afb21f25261df9f20d71fe2b1d9fe1864d2125b5ff9581835bc47cda136f96b7fd4b0383ec11bc38c33d9d82f18fe280fb3a783d6c36e44c061359616fe599c8b766dd7f1a24b0d2bff0b72da9e60d08e9035c678558720a1cfe56d0ac8497c3198336c22e987d0325aa2ba138211ed39179d993a72a1e6faa4d9d5173175ae857d22ae3f014686f62879c8b1dae45717c47e1c0eb0b492a656b3bdb297edaaa7f0b7c5a83f9516d0ffa196eb085f18774f"}; 

      return caPublicKeys.Any(s => currentCaPublicKey.Equals(s)); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex); 
      return false; 
     } 
} 

它工作正常,但我不知道是否我检查了正确的事情。任何建议从一些加密专家将不胜感激。

+0

PS:如果有人正在寻找通过使用CA Dropbox,它们在那里可用:https://github.com/dropbox/dropbox-sdk-python/blob/master/dropbox/trusted-certs.crt – John

+0

你的代码有多个未定义的符号,使它很难阅读。 (看起来他们正在编辑工件,比如'currentCaPk'。) – xxbbcc

回答

2

您的代码看起来正确地固定到根CA公钥。

HPKP要求您提供至少一个备份引脚,但我建议您遵循该指导。考虑到您固定到根CA,提供另一个根CA的公钥作为备份是适当的,以便在第一CA出现问题时缓解DoS的风险,例如停业。

当然,你的代码可以容纳多个公钥来反对,所以它只是一个添加额外的关键字到你的字符串列表的问题。

干杯

编辑2017年10月23日

这里是什么,我认为合理的根CA公钥钉扎和证书验证应该看起来像一个样本。这个快速样本是在WebApi项目中完成的,因此是锅炉板值控制器。

请注意,在我的示例中只使用一个(1)根CA公钥,并且如上所述,应提供一个备用引脚(最少2个数组元素)。

这是一个样品不打算被当作生产代码 - 我建议以下受到同行/安全审查:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Net; 
using System.Net.Http; 
using System.Net.Security; 
using System.Security.Cryptography.X509Certificates; 
using System.Web.Http; 

namespace CertPinPocClient.Controllers 
{ 
    public class ValuesController : ApiController 
    { 
     // GET api/values 
     public IEnumerable<string> Get() 
     { 
      ServicePointManager.ServerCertificateValidationCallback = new PinnedRootCaCertificate(new[] 
      { 
       "MIICCgKCAgEAzHYh7u+V5haaRSoGSVGm/gC4EYvZHkBR3/c/kQvTJeh1L9Bn/b7U1s7onw85SjvpZ28ohoT7p4vJRoNUBemR6hf3TM1mZmSE0tqnLGzBV9H4Nfrxx1+cubxYyYaOJ8iJfp1XslGGyZqQmUFFjWOUuU9cvOAbz4DqBIUn344JhG0xEHCf5IOF0gfuWE8yQC9vIjlveUQQ7dq/rDNZcQjqDhEb6DcF7za+1ZxjZdmtKewoYgDBPqzf66Gwi85BZsEcYFQTbjzvAhYaq4xPhJF6iPS4ihf+zjnMPxmy2oH1bm8n2fVuyxqV5JgIDU0ualx728UhfJUjcoBl57OLVsiJIdHFHpcDhN8Fn5QUGkNPgQqX27R1aw/+t2HfYTEsg6urH3aam8e7qRKUEXJs8qMKnXZ15aY0zlO7DLtfnK5tq2Cnu+HBBo4FlDhRO4kTBZOisFkvkEWI/Nj6jioOyMWsTsUvOdDK5KUpWZazpc3rwCvQy3KwBz6EyPU7ihrTm+nqqK5wiI9YwRcMjsPRBZfAur1cB0hNi+g98+2zzj+hwyR49KkOzFowp5MvXEWhnYDrY4cHSJ7zSdgMdO9HWPMke1HuKOUuUUUIpQMvPmFDAh4WQpAKqGvI/cOZeubnSwVMQra13QviYdlUeT56tFDTjgdbUNyBy0gxcFPVgTjzTj8CAwEAAQ==", 
      }).Valid; 

      var httpClient = new HttpClient 
      { 
       BaseAddress = new Uri("https://local.monitor.iontech.org") 
      }; 

      var httpResponseMessage = httpClient.GetAsync(new Uri("https://local.monitor.iontech.org/api/status/")).Result; 
      var result = httpResponseMessage.Content.ReadAsStringAsync().Result; 
      return new[] {result}; 
     } 
    } 

    public class PinnedRootCaCertificate 
    { 
     private readonly string[] _rootCaPublicKeys; 

     public PinnedRootCaCertificate(string[] rootCaPublicKeys) 
     { 
      _rootCaPublicKeys = rootCaPublicKeys; 
     } 

     public bool Valid(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyerrors) 
     { 
      if (sslpolicyerrors != SslPolicyErrors.None) return false; 

      var rootCertificate = SelfSignedCertificate(chain); 
      var publicKey = Convert.ToBase64String(rootCertificate.PublicKey.EncodedKeyValue.RawData); 
      return rootCertificate.Verify() && _rootCaPublicKeys.Contains(publicKey); 
     } 

     private X509Certificate2 SelfSignedCertificate(X509Chain chain) 
     { 
      foreach (var x509ChainElement in chain.ChainElements) 
      { 
       if (x509ChainElement.Certificate.SubjectName.Name != x509ChainElement.Certificate.IssuerName.Name) continue; 
       return x509ChainElement.Certificate; 
      } 
      throw new Exception("Self-signed certificate not found."); 
     } 
    } 
} 
+0

谢谢。有没有必要验证链?或者是事先由框架完成的? – John

+0

我并不是建议你不要做信任链验证,也不建议认证验证中的其他常见步骤应该被忽略。在上面的简单代码中,我说,“是的,看起来是正确的。”绝对应该重新使用框架。实际上,您发布的固定代码IMO应该替换为基于框架的代码。我正在使用自动柜员机,但是当我在我的机器前面有一段空闲时间时,我会详细说明一下。 –

+0

我刚刚编辑了包含* sample *代码的答案。 –

相关问题