2017-10-16 23 views
1

내 소프트웨어는 중요한 데이터를 검색하기 위해 HTTPS 연결을 사용하여 Dropbox에 연결합니다.C# .NET - 인증서 고정 (Pinning) 인증서 권한 - 올바르게 처리하고 있습니까?

중간자 (man-in-the-middle) 공격을 막기 위해 인증 기관을 고정하고 싶습니다.

지금까지 나는 다음과 같은 코드가 있습니다 :

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의 공개 키를 백업으로 제공하여 DoS의 위험을 완화하는 것이 적절합니다. 예를 들어, 사업 중단과 같은 첫 번째 CA에 무언가가 발생해야합니다.

물론 코드는 여러 개의 공개 키를 수용하므로 코드 목록에 추가 키를 추가하는 데 불과합니다.

건배

편집 여기 2017년 10월 23일

내가 합리적인 루트 CA 공개 키 피닝 (pinning) 및 CERT는 검증이 같아야 생각의 샘플입니다. 이 빠른 샘플은 WebApi 프로젝트에서 수행되었으므로 보일러 플레이트는 컨트롤러를 평가합니다.

내 샘플에는 루트 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는 프레임 워크 기반 코드로 대체되어야합니다. 나는 내 전화기, ATM에 있지만 내 기계 앞에 자유로운 순간이있을 때 좀 더 정교하게 다룰 것이다. –

+0

방금 ​​샘플 * 코드를 포함하도록 답변을 편집했습니다. –