Jestem dość nowy HTTPS/SSL/TLS
i jestem trochę zdezorientowany, co dokładnie klienci powinni przedstawić podczas uwierzytelniania za pomocą certyfikatów.
Piszę klienta Java, który musi wykonać proste POST
dane do konkretnego URL
. Ta część działa dobrze, jedynym problemem jest to, że należy to zrobić HTTPS
. Ta HTTPS
część jest dość łatwa w obsłudze (z HTTPclient
wbudowanym HTTPS
wsparciem Java lub z nią ), ale utknąłem na uwierzytelnianiu za pomocą certyfikatów klienta. Zauważyłem, że jest już bardzo podobne pytanie, którego nie wypróbowałem jeszcze z moim kodem (zrobię to wkrótce). Mój obecny problem polega na tym, że - cokolwiek robię - klient Java nigdy nie wysyła wraz z certyfikatem (mogę to sprawdzić za pomocą PCAP
zrzutów).
Chciałbym wiedzieć, co dokładnie klient powinien przedstawić serwerowi podczas uwierzytelniania za pomocą certyfikatów (szczególnie dla Javy - jeśli to w ogóle ma znaczenie)? Czy to JKS
plik, czy PKCS#12
? Co powinno w nich być; tylko certyfikat klienta lub klucz? Jeśli tak, to który klucz? Istnieje sporo zamieszania na temat różnych rodzajów plików, typów certyfikatów i tym podobnych.
Jak powiedziałem wcześniej, jestem nowy, HTTPS/SSL/TLS
więc doceniłbym również pewne podstawowe informacje (nie musi to być esej; zadowolę się linkami do dobrych artykułów).
źródło
Odpowiedzi:
W końcu udało mi się rozwiązać wszystkie problemy, więc odpowiem na własne pytanie. Są to ustawienia / pliki, którymi zarządzałem, aby rozwiązać konkretny problem;
The kluczy klienta jest PKCS # 12 Format pliku zawierającego
Aby go wygenerować, użyłem
pkcs12
na przykład polecenia OpenSSL ;Wskazówka: upewnij się, że masz najnowszą wersję OpenSSL, a nie wersję 0.9.8h, ponieważ wydaje się, że zawiera błąd, który nie pozwala poprawnie wygenerować plików PKCS # 12.
Ten plik PKCS # 12 zostanie wykorzystany przez klienta Java do przedstawienia certyfikatu klienta na serwerze, gdy serwer wyraźnie zażąda od klienta uwierzytelnienia. Zobacz artykuł Wikipedii na temat TLS, aby zobaczyć, jak działa protokół uwierzytelniania certyfikatu klienta (wyjaśnia również, dlaczego potrzebujemy tutaj klucza prywatnego klienta).
Przez zaufanych klienta jest proste JKS Format pliku zawierającego korzeniowych lub certyfikaty pośredniego urzędu certyfikacji . Te certyfikaty CA określą, z którymi punktami końcowymi będziesz mógł się komunikować, w tym przypadku pozwoli Twojemu klientowi połączyć się z dowolnym serwerem, który przedstawia certyfikat, który został podpisany przez jeden z CA urzędu certyfikacji.
Aby go wygenerować, możesz na przykład użyć standardowego narzędzia Java.
Korzystając z tego magazynu zaufanych certyfikatów, Twój klient będzie próbował przeprowadzić pełny uścisk protokołu SSL ze wszystkimi serwerami, które przedstawią certyfikat podpisany przez urząd certyfikacji
myca.crt
.Powyższe pliki są przeznaczone wyłącznie dla klienta. Jeśli chcesz również skonfigurować serwer, serwer potrzebuje własnych plików kluczy i magazynu zaufanych certyfikatów. Na tej stronie można znaleźć świetne instrukcje konfiguracji w pełni działającego przykładu zarówno dla klienta Java, jak i serwera (za pomocą Tomcat) .
Problemy / uwagi / wskazówki
-Djavax.net.debug=ssl
ale jest bardziej uporządkowany i (prawdopodobnie) łatwiejszy do interpretacji, jeśli nie czujesz się komfortowo z wynikiem debugowania Java SSL.Korzystanie z biblioteki httpclient Apache jest całkowicie możliwe. Jeśli chcesz użyć klienta httpclient, po prostu zastąp docelowy adres URL odpowiednikiem HTTPS i dodaj następujące argumenty JVM (takie same dla każdego innego klienta, niezależnie od biblioteki, której chcesz używać do wysyłania / odbierania danych przez HTTP / HTTPS) :
źródło
SSLContext
jak w odpowiedzi @ Magnus.Inne odpowiedzi pokazują, jak globalnie skonfigurować certyfikaty klienta. Jeśli jednak chcesz programowo zdefiniować klucz klienta dla jednego konkretnego połączenia, zamiast globalnie zdefiniować go dla każdej aplikacji uruchomionej na JVM, możesz skonfigurować własny tekst SSLContext w następujący sposób:
źródło
sslContext = SSLContexts.custom().loadTrustMaterial(keyFile, PASSWORD).build();
. Nie mogłem z tym pracowaćloadKeyMaterial(...)
.loadKeyMaterial(keystore, keyPassphrase.toCharArray())
kodzie ”!SSLContext
.Plik JKS to tylko kontener certyfikatów i par kluczy. W scenariuszu uwierzytelnienia po stronie klienta różne części kluczy będą znajdować się tutaj:
Rozdzielenie magazynu zaufanych certyfikatów i magazynu kluczy nie jest obowiązkowe, ale zalecane. Mogą być tym samym plikiem fizycznym.
Aby ustawić lokalizacje systemu plików dwóch sklepów, użyj następujących właściwości systemu:
i na serwerze:
Aby wyeksportować certyfikat klienta (klucz publiczny) do pliku, aby móc go skopiować na serwer, użyj
Aby zaimportować klucz publiczny klienta do magazynu kluczy serwera, użyj (jak wspomniano w plakacie, zostało to już zrobione przez administratorów serwera)
źródło
Maven pom.xml:
Kod Java:
źródło
configureRequest()
ustawiania proxy projektu klienta jest prawidłowa?Dla tych z Was, którzy po prostu chcą skonfigurować uwierzytelnianie dwukierunkowe (certyfikaty serwera i klienta), połączenie tych dwóch linków doprowadzi Cię tam:
Konfiguracja dwukierunkowego uwierzytelniania:
https://linuxconfig.org/apache-web-server-ssl-authentication
Nie musisz używać wspomnianego pliku konfiguracyjnego openssl; po prostu użyj
$ openssl genrsa -des3 -out ca.key 4096
$ openssl req -new -x509 -dni 365 -key ca.key -out ca.crt
wygenerować własny certyfikat CA, a następnie wygenerować i podpisać klucze serwera i klienta za pomocą:
$ openssl genrsa -des3 -out server.key 4096
$ openssl req -new -key server.key -out server.csr
$ openssl x509 -req -dni 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 100 -out server.crt
i
$ openssl genrsa -des3 -out client.key 4096
$ openssl req -new -key client.key -out client.csr
$ openssl x509 -req -dni 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 101 -out client.crt
Przez resztę postępuj zgodnie z instrukcjami w linku. Zarządzanie certyfikatami dla Chrome działa tak samo, jak w przykładzie dla wspomnianego Firefoxa.
Następnie skonfiguruj serwer za pomocą:
https://www.digitalocean.com/community/tutorials/how-to-create-a-ssl-certificate-on-apache-for-ubuntu-14-04
Zauważ, że już utworzyłeś serwer .crt i .key, więc nie musisz już robić tego kroku.
źródło
server.key
nie używajclient.key
Połączyłem się z bankiem za pomocą dwukierunkowego protokołu SSL (certyfikat klienta i serwera) z Spring Boot. Opisz więc tutaj wszystkie moje kroki, mam nadzieję, że to komuś pomoże (najprostsze działające rozwiązanie, jakie znalazłem):
Wygeneruj żądanie sertertyfikatu:
Wygeneruj klucz prywatny:
Wygeneruj żądanie certyfikatu:
Zachowaj
user.key
(i hasło) i wyślij prośbę o certyfikatuser.csr
do banku w celu uzyskania mojego certyfikatuOtrzymaj 2 certyfikat: mój główny certyfikat klienta i główny certyfikat
clientId.crt
banku:bank.crt
Utwórz magazyn kluczy Java (wprowadź hasło klucza i ustaw hasło magazynu kluczy):
Nie zwracaj uwagi na wyjściu:
unable to write 'random state'
. Java PKCS12keystore.p12
utworzona.Dodaj do magazynu kluczy
bank.crt
(dla uproszczenia użyłem jednego magazynu kluczy):Sprawdź certyfikaty magazynu kluczy przez:
Gotowy na kod Java :) Użyłem Spring Boot
RestTemplate
z dodatkowąorg.apache.httpcomponents.httpcore
zależnością:źródło
Biorąc pod uwagę plik p12 z certyfikatem i kluczem prywatnym (na przykład wygenerowanym przez openssl), następujący kod użyje go do określonego połączenia HttpsURLConnection:
SSLContext
Zajmuje trochę czasu, aby zainicjować, więc warto ją buforować.źródło
Myślę, że poprawką tutaj był typ magazynu kluczy, pkcs12 (pfx) zawsze mają klucz prywatny, a typ JKS może istnieć bez klucza prywatnego. O ile nie określisz w swoim kodzie lub nie wybierzesz certyfikatu za pomocą przeglądarki, serwer nie będzie wiedział, że reprezentuje klienta na drugim końcu.
źródło