5

Ho bisogno di un buon modo per implementare il certificato o il blocco della chiave pubblica in un'applicazione Windows 10 Universal. Tutto il codice è in C# e tutte le connessioni sono HTTPS, quindi qualcosa per la classe Windows.Web.Http.HttpClient sarebbe fantastico. C'è una semplice classe/libreria, o almeno una guida passo-passo, su come implementare questa roba che può essere fatta in sicurezza da qualcuno che non conosce i dettagli arcani dei certificati X.509 e così via?Blocco del certificato in Windows 10 Applicazione universale

Alcune cose che ho trovato parlano dell'utilizzo del codice nativo o di librerie di terze parti come OpenSSL (molto complicato!). La cosa migliore che ho trovato è il this question sul pinning in WP8.0, che include un esempio di codice che dovrebbe funzionare su WP8.1 e si spera anche su Win10, ma è un po 'brutto e confuso, e non sono sicuro di come richiedere che il certificato del server è uno di quelli appuntati quando si invia la richiesta con le informazioni sensibili. Controllare in anticipo non sembra sicuro a causa degli attacchi del tempo di controllo/tempo di utilizzo (TOCTOU) (a meno che la funzione HttpRequestMessage. TransportInformation apra la connessione e quindi la tenga aperta, quindi non c'è possibilità che un attaccante ottenga un uomo -in-the-middle position su una nuova connessione). Idealmente ci sarebbe un modo per filtrare HttpClient in modo che si connetta solo ai server con certificati appuntati, ma la cosa più vicina che riesco a fare fa esattamente il contrario (ignora alcuni errori di cert, come parlato su here) tramite la proprietà HttpBaseProtocolFilter.IgnorableServerCertificateErrors, che non sembra avere alcuna opzione per limitare i certificati validi.

Qualcuno ha una buona soluzione qui? Se l'approccio HttpRequestMessage.TransportInformation (con codice di convalida del certificato personalizzato) è l'unica opzione, è sicuro contro gli attacchi TOCTOU verificare la proprietà prima di inviare la richiesta?

+0

Ciao, sto avendo gli stessi problemi come te, hai avuto fortuna su come farlo? – toroveneno

risposta

-1

L'articolo seguente ha una buona soluzione. Provalo.

https://www.codeproject.com/Articles/849510/Certificate-Pinning-on-Windows-Phone

io non hanno molta esperienza in UWP ma in Window app 8.1 negozio ha package.appxmanifest di file che consente di definire i certificati di origine su "scheda di dichiarazione" così, il codice è possibile fare una convalida corretta.

L'articolo seguente ha anche alcuni buoni modi per stabilire come proteggere l'app e le connessioni HTTP. https://blogs.windows.com/buildingapps/2015/10/13/create-more-secure-apps-with-less-effort-10-by-10/#bWSeoR0pMyW2H8fg.97

1

Avete dato un'occhiata all'evento ServerCustomValidationRequested off di HttpBaseProtocolFilter? La parte difficile per me era estrarre il certificato pubblico dall'oggetto Certificato. Per farlo ho dovuto inserire il pacchetto System.Security.Cryptography.X509Certificates nuget. Il mio codice è simile al seguente:

private void DoIt() 
{ 
    using (var filter = new HttpBaseProtocolFilter()) 
    { 
     filter.ServerCustomValidationRequested += FilterOnServerCustomValidationRequested; 
     var httpClient = new Windows.Web.Http.HttpClient(filter); 
     var myString = await httpClient.GetStringAsync(new Uri("https://myserver.com")); 
     // I guess we should be kind and unsubscribe? 
     filter.ServerCustomValidationRequested -= FilterOnServerCustomValidationRequested; 
    } 
} 

private void FilterOnServerCustomValidationRequested(HttpBaseProtocolFilter sender, HttpServerCustomValidationRequestedEventArgs args) 
{ 
    if (!IsCertificateValid(args.RequestMessage, args.ServerCertificate, args.ServerCertificateErrors)) 
    { 
     args.Reject(); 
    } 
} 

private bool IsCertificateValid(Windows.Web.Http.HttpRequestMessage httpRequestMessage, Certificate cert, IReadOnlyList<ChainValidationResult> sslPolicyErrors) 
{ 
    // disallow self-signed certificates or certificates with errors 
    if (sslPolicyErrors.Count > 0) 
    { 
     return false; 
    } 

    if (RequestRequiresCheck(httpRequestMessage.RequestUri)) 
    { 
     var certificateSubject = cert?.Subject; 
     bool subjectMatches = certificateSubject == CERTIFICATE_COMMON_NAME; 

     var certArray = cert?.GetCertificateBlob().ToArray(); 
     var x509Certificate2 = new X509Certificate2(certArray); 
     var certificatePublicKey = x509Certificate2.GetPublicKey(); 
     var certificatePublicKeyString = Convert.ToBase64String(certificatePublicKey); 
     bool publicKeyMatches = certificatePublicKeyString == CERTIFICATE_PUBLIC_KEY; 

     return subjectMatches && publicKeyMatches; 
    } 

    return true; 
} 

private bool RequestRequiresCheck(Uri uri) 
{ 
    return uri.IsAbsoluteUri && 
      uri.AbsoluteUri.StartsWith("https://", StringComparison.CurrentCultureIgnoreCase) && 
      uri.AbsoluteUri.StartsWith(BASE_URL, StringComparison.CurrentCultureIgnoreCase); 
} 
+0

Per inciso, ho ottenuto la soluzione per l'estrazione della chiave pubblica da qui: https://stackoverflow.com/a/38126387/40783. Mi piacerebbe farlo senza un riferimento aggiuntivo a nuget, magari tramite 'Windows.Security.Cryptography.Core.PersistedKeyProvider.OpenPublicKeyFromCertificate' ma non sono riuscito a ottenere gli argomenti corretti per farlo funzionare e restituire il numero corretto di byte. Si prega di condividere se qualcuno può trovare una soluzione più pulita. –