5

Potrzebuję dobrego sposobu na zaimplementowanie przypinania za pomocą certyfikatu lub klucza publicznego w uniwersalnej aplikacji systemu Windows 10. Cały kod jest w języku C#, a wszystkie połączenia to HTTPS, więc coś dla klasy Windows.Web.Http.HttpClient byłoby świetne. Czy istnieje prosta klasa/biblioteka lub przynajmniej przewodnik krok po kroku, jak wdrożyć te rzeczy, które mogą być bezpiecznie wykonane przez kogoś, kto nie zna tajemnych szczegółów certyfikatów X.509 i tak dalej?Ściąganie certyfikatu w uniwersalnej aplikacji Windows 10

Niektóre rzeczy, o których mówiłem, mówią o używaniu kodu natywnego lub bibliotek innych firm, takich jak OpenSSL (bardzo skomplikowane!). Najlepszą rzeczą, jaką znalazłem jest this question o przypinaniu w WP8.0, która zawiera próbkę kodu, która powinna działać na WP8.1 i, miejmy nadzieję, także na Win10, ale jest trochę brzydka i myląca, i nie jestem pewna, jak wymagać że certyfikat serwera jest jednym z pinezek podczas wysyłania żądania z informacjami wrażliwymi na numer. Sprawdzanie wcześniej nie wydaje się bezpieczne z powodu ataków TOCTOU (czas czekania/czas użycia) (chyba że funkcja HttpRequestMessage. TransportInformation otwiera połączenie, a następnie je otwiera, więc nie ma szans, aby napastnik zyskał człowieka -na środkowej pozycji na nowym połączeniu). Idealnie byłoby znaleźć sposób na filtrowanie HttpClient, aby łączył się on tylko z serwerami z przypiętymi certyfikatami, ale najbliższa rzecz, jaką mogę znaleźć, działa dokładnie odwrotnie (zignoruj ​​pewne błędy certyfikatów, o których mówiono o here) za pośrednictwem właściwości HttpBaseProtocolFilter.IgnorableServerCertificateErrors, która wydaje się nie mieć żadnej możliwości ograniczenia ważnych certyfikatów.

Czy ktoś ma tutaj dobre rozwiązanie? Jeśli podejście HttpRequestMessage.TransportInformation (z niestandardowym kodem weryfikacji certyfikatu) jest jedyną opcją, czy jest bezpieczne przed atakami TOCTOU, aby sprawdzić tę właściwość przed wysłaniem żądania?

+0

Witam, mam takie same problemy jak ty, czy miałeś szczęście, jak to zrobić? – toroveneno

Odpowiedz

-1

Poniższy artykuł ma dobre rozwiązanie. Spróbuj.

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

nie mam dużego doświadczenia w UWP ale w Window 8,1 sklepowych aplikacji ma package.appxmanifest plik, który pozwala na określenie swoich certyfikatów głównych na „karcie zgłoszenia” tak, na kodzie można zrobić odpowiednią walidację.

Poniższy artykuł zawiera również kilka dobrych wskazówek na temat zabezpieczania aplikacji i połączeń HTTP. https://blogs.windows.com/buildingapps/2015/10/13/create-more-secure-apps-with-less-effort-10-by-10/#bWSeoR0pMyW2H8fg.97

1

Czy rzuciłeś okiem na zdarzenie ServerCustomValidationRequested off HttpBaseProtocolFilter? Najtrudniejszą częścią dla mnie było wyodrębnienie certyfikatu publicznego z obiektu certyfikatu. Aby to zrobić, musiałem przynieść pakiet nuget System.Security.Cryptography.X509Certificates. Mój kod wygląda tak:

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

Nawiasem mówiąc, mam rozwiązanie do wyodrębniania klucza publicznego stąd: https://stackoverflow.com/a/38126387/40783. Chciałbym to zrobić bez dodatkowego odwołania nuget, może za pośrednictwem 'Windows.Security.Cryptography.Core.PersistedKeyProvider.OpenPublicKeyFromCertificate' ale nie mogłem uzyskać poprawne argumenty, aby działało i zwracają poprawną liczbę bajtów. Udostępniaj, jeśli ktoś może znaleźć czystsze rozwiązanie. –