2014-06-14 1 views
11

Können Sie HttpClient zwingen, nur einem einzelnen Zertifikat zu vertrauen?Force HttpClient, um einzelnes Zertifikat zu vertrauen

Ich weiß, was Sie tun können:

WebRequestHandler handler = new WebRequestHandler(); 
X509Certificate2 certificate = GetMyX509Certificate(); 
handler.ClientCertificates.Add(certificate); 
HttpClient client = new HttpClient(handler); 

Aber wird diese Kraft es nur das einzige Zertifikat vertrauen, oder wird es, dass certifate und alle Zertifikate vertrauen, dass fx. GlobalSign kann verifizieren?

Grundsätzlich möchte ich sicherstellen, dass es nur mein Server/Zertifikat sein kann, mit dem mein Client spricht.

+0

Gute Frage. Es ist großartig zu sehen, dass Sie proaktive Maßnahmen ergreifen, um den Kanal zu härten. – jww

Antwort

12

Können Sie Httpclient zwingen, nur ein einziges Zertifikat vertrauen? ... Grundsätzlich möchte ich sicherstellen, dass es nur mein Server/Zertifikat sein kann, mit dem mein Client spricht.

Ja. Aber welche Art von Zertifikat? Server oder CA? Beispiele für beide folgen.

Es könnte auch besser sein, den öffentlichen Schlüssel als das Zertifikat im Falle eines Servers zu pinnen. Das liegt daran, dass einige Organisationen wie Google ihre Serverzertifikate alle 30 Tage oder so drehen, um die CRLs für mobile Clients klein zu halten. Die Organisationen werden jedoch den öffentlichen Schlüssel denselben erneut zertifizieren.


Hier ist ein Beispiel für die CA von Use a particular CA for a SSL connection Pinning. Es erfordert nicht, das Zertifikat in einem Zertifikatspeicher zu platzieren. Sie können die CA in Ihrer App herumtragen.

static bool VerifyServerCertificate(object sender, X509Certificate certificate, 
    X509Chain chain, SslPolicyErrors sslPolicyErrors) 
{ 
    try 
    { 
     String CA_FILE = "ca-cert.der"; 
     X509Certificate2 ca = new X509Certificate2(CA_FILE); 

     X509Chain chain2 = new X509Chain(); 
     chain2.ChainPolicy.ExtraStore.Add(ca); 

     // Check all properties (NoFlag is correct) 
     chain2.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag; 

     // This setup does not have revocation information 
     chain2.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; 

     // Build the chain 
     chain2.Build(new X509Certificate2(certificate)); 

     // Are there any failures from building the chain? 
     if (chain2.ChainStatus.Length == 0) 
      return false; 

     // If there is a status, verify the status is NoError 
     bool result = chain2.ChainStatus[0].Status == X509ChainStatusFlags.NoError; 
     Debug.Assert(result == true); 

     return result; 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine(ex); 
    } 

    return false; 
} 

Ich habe nicht herausgefunden, wie diese Kette zu verwenden (chain2 oben) standardmäßig, so dass es für den Rückruf nicht erforderlich ist. Das heißt, installieren Sie es auf dem SSL-Socket und die Verbindung wird "einfach funktionieren".

Und ich habe nicht herausgefunden, wie es installieren, so dass es in den Rückruf übergeben. Das heißt, ich muss die Kette für jeden Aufruf des Rückrufs erstellen, da meine chain2 nicht in die Funktionen wie chain übergeben wird.


Hier ist ein Beispiel von Certificate and Public Key Pinning das Server-Zertifikat von OWASP des Pinning. Es erfordert nicht, das Zertifikat in einem Zertifikatspeicher zu platzieren. Sie können das Zertifikat oder den öffentlichen Schlüssel in Ihrer App mit sich herumtragen.

// Encoded RSAPublicKey 
private static String PUB_KEY = "30818902818100C4A06B7B52F8D17DC1CCB47362" + 
    "C64AB799AAE19E245A7559E9CEEC7D8AA4DF07CB0B21FDFD763C63A313A668FE9D764E" + 
    "D913C51A676788DB62AF624F422C2F112C1316922AA5D37823CD9F43D1FC54513D14B2" + 
    "9E36991F08A042C42EAAEEE5FE8E2CB10167174A359CEBF6FACC2C9CA933AD403137EE" + 
    "2C3F4CBED9460129C72B0203010001"; 

public static void Main(string[] args) 
{ 
    ServicePointManager.ServerCertificateValidationCallback = PinPublicKey; 
    WebRequest wr = WebRequest.Create("https://encrypted.google.com/"); 
    wr.GetResponse(); 
} 

public static bool PinPublicKey(object sender, X509Certificate certificate, X509Chain chain, 
           SslPolicyErrors sslPolicyErrors) 
{ 
    if (null == certificate) 
    return false; 

    String pk = certificate.GetPublicKeyString(); 
    if (pk.Equals(PUB_KEY)) 
    return true; 

    // Bad dog 
    return false; 
} 
+0

Ich habe es so gemacht, wie meine Antwort sagt. Ich habe hier ein paar gute Dinge gelernt. Vielen Dank! – Typist

+0

@ André Snede Hansen, Danke für die Nachfrage. – Typist

+1

if (chain2.ChainStatus.Length == 0) test sollte false zurückgeben, nein? – Vince

-9

Client kann ServerCertificateValidationCallback wie unten verwenden -

System.Net.ServicePointManager.ServerCertificateValidationCallback += 
    delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, 
          System.Security.Cryptography.X509Certificates.X509Chain chain, 
          System.Net.Security.SslPolicyErrors sslPolicyErrors) 
     { 
      return true; 
     }; 
+3

-1. Es gibt absolut keine Überprüfung. Das OP hat darum gebeten, einem einzelnen Zertifikat zu vertrauen, und die angegebene Antwort vertraut allem (sogar dem falschen Zertifikat). Der Vorschlag unterscheidet sich nicht von den Problemen, die in [Der gefährlichste Code der Welt: Validierung von SSL-Zertifikaten in Nicht-Browser-Software] (http://www.cs.utexas.edu/~shmat/shmat_ccs12.pdf) behandelt wurden. – jww

+0

Super! @jww, ich habe dich. – Typist

2

Für alle, die in Zukunft über das kommt tou, dass einige Zertifizierungsstellen nicht mehr Zertifikate mit dem gleichen öffentlichen Schlüssel erneut ausgeben wird, wenn das Zertifikat erneuert wird, sollten sich bewusst sein. Wir hatten dieses Problem speziell mit Globalsign, das uns mit dem sehr schwierigen logistischen Problem der Aktualisierung der Client-Software mit neuen Public-Key-Pinning-Details für alle unsere Kunden in sehr kurzer Zeit zurückließ, obwohl ihre veröffentlichten Richtliniendokumente sagten, dass sie die Option zur Verfügung stellten den öffentlichen Schlüssel wiederverwenden.Wenn dies ein Problem für Sie sein könnte, bestätigen Sie die Richtlinien Ihres Zertifikatsanbieters im Voraus und verwenden Sie Globalsign nicht!