2017-10-16 6 views
1

Mon logiciel se connecte à Dropbox en utilisant une connexion HTTPS afin de récupérer certaines données sensibles.C# .NET - Épinglage des certificats Autorités - Je le fais correctement?

Je voudrais épingler les autorités de certificats afin d'éviter une attaque de type man-in-the-middle.

Jusqu'à présent, j'ai le code suivant:

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; 
     } 
} 

Il fonctionne très bien, mais je ne sais pas si je vérifie les bonnes choses. Tous les conseils de certains experts en cryptographie seraient grandement appréciés.

+0

PS: quelqu'un En cas est à la recherche de CA utilisé par Dropbox, ils sont disponibles ici: https://github.com/dropbox/dropbox-sdk-python/blob/master/dropbox/trusted-certs.crt – John

+0

Votre code a plusieurs symboles indéfinis qui rendent la lecture difficile. (On dirait qu'ils éditent des artefacts, comme 'currentCaPk'.) – xxbbcc

Répondre

2

Votre code semble correct pour épingler à la clé publique racine CA. Toutefois, HPKP exige que vous fournissiez au moins une broche de sauvegarde, et je vous recommande de suivre cette directive. Étant donné que vous épinglez sur une autorité de certification racine, il convient de fournir la clé publique d'une autre autorité de certification racine en tant que sauvegarde afin d'atténuer le risque de DoS en cas de problème avec la première autorité de certification, par exemple en panne.

Bien sûr, votre code peut contenir plusieurs clés publiques contre lesquelles il est possible d'ajouter une clé supplémentaire à votre liste de chaînes.

Vive

EDIT 2017.10.23

Voici un échantillon de ce que je pense Racine raisonnable CA épinglage clé publique et validation Cert devrait ressembler. Cet échantillon rapide a été fait dans un projet WebApi, donc le contrôleur de valeurs de plaque de chaudière.

Veuillez noter que seulement une (1) clé publique CA racine est utilisée dans mon échantillon, et comme mentionné ci-dessus, une broche de sauvegarde doit être fournie (minimum 2 éléments de tableau).

Ceci est un exemple et non destinés à être pris comme code de production - Je suggère que les points suivants soient soumis à des pairs/examen de la sécurité:

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

Merci. N'y a-t-il pas besoin de vérifier la chaîne? Ou est-ce fait par le cadre à l'avance? – John

+0

Je ne suggère pas que vous ne voudriez pas faire la validation de Trust Chain, ni suggérer que les autres étapes habituelles de la validation de cert devraient être ignorées. Dans le code simple ci-dessus, je dis, "oui, ça a l'air juste." Re en utilisant le cadre, absolument, vous devriez. En fait, le code d'épinglage que vous avez posté, IMO, devrait être remplacé par du code basé sur le framework. Je suis sur mon téléphone, ATM, mais j'élaborerai un peu quand j'ai un moment libre devant ma machine. –

+0

Je viens d'éditer la réponse pour inclure le code * sample *. –