Mam klienta usługi sieciowej Java, który korzysta z usługi sieciowej za pośrednictwem protokołu HTTPS.
import javax.xml.ws.Service;
@WebServiceClient(name = "ISomeService", targetNamespace = "http://tempuri.org/", wsdlLocation = "...")
public class ISomeService
extends Service
{
public ISomeService() {
super(__getWsdlLocation(), ISOMESERVICE_QNAME);
}
Kiedy łączę się z adresem URL usługi ( https://AAA.BBB.CCC.DDD:9443/ISomeService
), pojawia się wyjątek java.security.cert.CertificateException: No subject alternative names present
.
Aby to naprawić, najpierw uruchomiłem openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt
i otrzymałem następującą zawartość w pliku certs.txt
:
CONNECTED(00000003)
---
Certificate chain
0 s:/CN=someSubdomain.someorganisation.com
i:/CN=someSubdomain.someorganisation.com
-----BEGIN CERTIFICATE-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-----END CERTIFICATE-----
---
Server certificate
subject=/CN=someSubdomain.someorganisation.com
issuer=/CN=someSubdomain.someorganisation.com
---
No client certificate CA names sent
---
SSL handshake has read 489 bytes and written 236 bytes
---
New, TLSv1/SSLv3, Cipher is RC4-MD5
Server public key is 512 bit
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : RC4-MD5
Session-ID: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Session-ID-ctx:
Master-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Key-Arg : None
Start Time: 1382521838
Timeout : 300 (sec)
Verify return code: 21 (unable to verify the first certificate)
---
AFAIK, teraz muszę
- wyodrębnij część
certs.txt
między-----BEGIN CERTIFICATE-----
a-----END CERTIFICATE-----
, - zmodyfikuj go tak, aby nazwa certyfikatu była równa
AAA.BBB.CCC.DDD
i - następnie zaimportuj wynik za pomocą
keytool -importcert -file fileWithModifiedCertificate
(gdziefileWithModifiedCertificate
jest wynikiem operacji 1 i 2).
Czy to jest poprawne?
Jeśli tak, jak dokładnie mogę sprawić, by certyfikat z kroku 1 działał z adresem IP opartym na adresie IP ( AAA.BBB.CCC.DDD
)?
Aktualizacja 1 (23.10.2013 15:37 MSK): W odpowiedzi na podobne pytanie przeczytałem:
Jeśli nie masz kontroli nad tym serwerem, użyj jego nazwy hosta (pod warunkiem, że istnieje co najmniej CN pasująca do tej nazwy hosta w istniejącym certyfikacie).
Co dokładnie oznacza „używać”?
źródło
Mam ten sam problem i rozwiązałem go za pomocą tego kodu. Ten kod umieściłem przed pierwszym wywołaniem moich usług sieciowych.
To proste i działa dobrze.
Oto oryginalne źródło.
źródło
return hostname.equals("localhost");
, jeśli chcesz to zrobić. Jestif
to całkowicie zbędne.HttpsURLConnection connection = (HttpsURLConnection) obj.openConnection();
. Czy to ignoruje każdy certyfikat? Odkąd widziałem, że takie obejście jest podatne na zagrożenia. Dziękuję Ci!To jest stare pytanie, ale miałem ten sam problem podczas przechodzenia z JDK 1.8.0_144 na jdk 1.8.0_191
Znaleźliśmy wskazówkę w dzienniku zmian:
Changelog
dodaliśmy następującą dodatkową właściwość systemową, która pomogła w naszym przypadku rozwiązać ten problem:
źródło
Weryfikacja tożsamości certyfikatu jest przeprowadzana na podstawie żądań klienta.
Gdy klient używa
https://xxx.xxx.xxx.xxx/something
(gdziexxx.xxx.xxx.xxx
jest adres IP), tożsamość certyfikatu jest sprawdzana w odniesieniu do tego adresu IP (teoretycznie tylko przy użyciu rozszerzenia IP SAN).Jeśli Twój certyfikat nie ma IP SAN, ale DNS SAN (lub jeśli nie ma DNS SAN, nazwy pospolitej w nazwie wyróżniającej podmiotu), możesz sprawić, że zadziała, używając zamiast tego adresu URL z tą nazwą hosta (lub nazwą hosta dla których certyfikat byłby ważny, jeśli istnieje wiele możliwych wartości). Na przykład, jeśli certyfikat ma nazwę dla
www.example.com
, użyjhttps://www.example.com/something
.Oczywiście będziesz potrzebować tej nazwy hosta, aby rozwiązać ten adres IP.
Ponadto, jeśli istnieją jakiekolwiek sieci DNS SAN, CN w nazwie wyróżniającej podmiotu zostanie zignorowana, dlatego w tym przypadku należy użyć nazwy pasującej do jednej z sieci DNS SAN.
źródło
http://www.example.com/someservice
. Czy jest to prawidłowe, że w celu zaświadczenia do pracy z adresu IP (z siedzibąhttps://AAA.BBB.CCC.DDD:9443/ISomeService
), muszę ustawić wszystkieCN
pola doAAA.BBB.CCC.DDD
(zastąpieniesomeSubdomain.someorganisation.com
przezAAA.BBB.CCC.DDD
w pliku powyżej) i zaimportować wynikowy plik certyfikatu?/etc/hosts
plik lub jego odpowiednikAby zaimportować certyfikat:
openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt
Spowoduje to wyodrębnienie certyfikatów w formacie PEM.openssl x509 -in certs.txt -out certs.der -outform DER
sudo keytool -importcert -file certs.der -keystore <path-to-cacerts>
Domyślne hasło cacerts to „changeit”.Jeśli certyfikat został wystawiony dla nazwy FQDN i próbujesz połączyć się za pomocą adresu IP w kodzie Java, prawdopodobnie powinno to zostać naprawione w kodzie, a nie z samym certyfikatem. Zmień kod, aby łączyć się przez FQDN. Jeśli nazwa FQDN nie jest rozpoznawalna na twoim komputerze deweloperskim, po prostu dodaj ją do pliku hosts lub skonfiguruj swój komputer z serwerem DNS, który może rozpoznać tę nazwę FQDN.
źródło
Naprawiłem ten problem we właściwy sposób, dodając nazwy alternatywne tematu w certyfikacie, zamiast wprowadzać jakiekolwiek zmiany w kodzie lub wyłączając SSL, w przeciwieństwie do tego, co sugerują inne odpowiedzi. Jeśli widzisz wyraźnie, wyjątek mówi, że „Brakuje nazw alternatywnych tematu”, więc należy je dodać
Proszę spojrzeć na ten link, aby zrozumieć krok po kroku .
Powyższy błąd oznacza, że w pliku JKS brakuje wymaganej domeny, na której próbujesz uzyskać dostęp do aplikacji. Aby dodać wiele domen, musisz użyć protokołu Open SSL i narzędzia klucza
echo '[ subject_alt_name ]' >> openssl.cnf
echo 'subjectAltName = DNS:example.mydomain1.com, DNS:example.mydomain2.com, DNS:example.mydomain3.com, DNS: localhost'>> openssl.cnf
openssl req -x509 -nodes -newkey rsa:2048 -config openssl.cnf -extensions subject_alt_name -keyout private.key -out self-signed.pem -subj '/C=gb/ST=edinburgh/L=edinburgh/O=mygroup/OU=servicing/CN=www.example.com/[email protected]' -days 365
Wyeksportuj plik klucza publicznego (.pem) do formatu PKS12. Spowoduje to wyświetlenie monitu o hasło
Utwórz plik JKS z samodzielnie podpisanego PEM (Keystore)
Wygeneruj certyfikat z pliku Keystore lub JKS
Ponieważ powyższy certyfikat jest samopodpisany i nie jest sprawdzany przez CA, należy go dodać do Truststore (plik Cacerts w poniższej lokalizacji dla MAC, dla Windows, dowiedz się, gdzie jest zainstalowany pakiet JDK).
Oryginalna odpowiedź zamieszczona pod tym linkiem tutaj .
źródło
Możesz nie chcieć wyłączać całej weryfikacji SSL, więc możesz po prostu wyłączyć weryfikację nazwy hosta za pomocą tego, co jest nieco mniej przerażające niż alternatywa:
[EDYTOWAĆ]
Jak wspomniano w conapart3,
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
jest teraz przestarzały, więc może zostać usunięty w późniejszej wersji, więc w przyszłości możesz być zmuszony do zainstalowania własnego, chociaż nadal powiedziałbym, że unikałbym rozwiązań, w których cała weryfikacja jest wyłączona.źródło
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
jest teraz przestarzała.mój problem z wyświetlaniem tego błędu został rozwiązany przy użyciu pełnego adresu URL „qatest.ourCompany.com/webService” zamiast tylko „qatest / webService”. Powodem było to, że nasz certyfikat bezpieczeństwa zawierał symbol wieloznaczny, tj. „* .OurCompany.com”. Kiedy podałem pełny adres, wyjątek zniknął. Mam nadzieję że to pomoże.
źródło
Odpowiedziałem już na https://stackoverflow.com/a/53491151/1909708 .
Nie udaje się to, ponieważ ani nazwa pospolita certyfikatu (
CN
w certyfikacjiSubject
), ani żadna z nazw alternatywnych (Subject Alternative Name
w certyfikacie) nie są zgodne z docelową nazwą hosta lub adresem IP.Na przykład z maszyny JVM, podczas próby połączenia się z adresem IP (
WW.XX.YY.ZZ
), a nie nazwą DNS ( https://stackoverflow.com ), połączenie HTTPS nie powiedzie się, ponieważ certyfikat przechowywany w magazynie zaufanych certyfikatów javacacerts
oczekuje nazwy pospolitej (lub alternatywna nazwa certyfikatu, taka jak stackexchange.com lub * .stackoverflow.com itp.), aby dopasować adres docelowy.Sprawdź: https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#HostnameVerifier
Powyżej przekazano zaimplementowany
HostnameVerifier
obiekt, który zawsze zwracatrue
:źródło
Do butów wiosennych
RestTemplate
:org.apache.httpcomponents.httpcore
zależnośćUżyj
NoopHostnameVerifier
dla fabryki SSL:źródło
Otrzymałem to pytanie po tym, jak otrzymałem ten sam komunikat o błędzie. Jednak w moim przypadku mieliśmy dwa adresy URL z różnymi subdomenami ( http://example1.xxx.com/someservice i http://example2.yyy.com/someservice ), które były kierowane na ten sam serwer. Ten serwer miał tylko jeden certyfikat wieloznaczny dla domeny * .xxx.com. Podczas korzystania z usługi za pośrednictwem drugiej domeny znaleziony certyfikat (* .xxx.com) nie pasuje do żądanej domeny (* .yyy.com) i pojawia się błąd.
W takim przypadku nie powinniśmy próbować naprawiać takiej wiadomości o błędzie poprzez obniżenie bezpieczeństwa SSL, ale powinniśmy sprawdzić serwer i certyfikaty na nim.
źródło
źródło
Przechodziłem przez 2-drożny SSL w springboot. Zrobiłem całą poprawną konfigurację serwera tomcat usługi i wywołującego usługę RestTemplate. ale otrzymywałem błąd: „java.security.cert.CertificateException: brak alternatywnych nazw tematów”
Po przejściu przez rozwiązania stwierdziłem, że JVM potrzebuje tego certyfikatu, w przeciwnym razie wyświetla błąd uzgadniania.
Teraz, jak dodać to do JVM.
przejdź do pliku jre / lib / security / cacerts. musimy dodać nasz plik certyfikatu serwera do tego pliku cacerts jvm.
Polecenie dodania certyfikatu serwera do pliku cacerts za pomocą wiersza poleceń w systemie Windows.
C: \ Program Files \ Java \ jdk1.8.0_191 \ jre \ lib \ security> keytool -import -noprompt -trustcacerts -alias sslserver -file E: \ spring_cloud_sachin \ ssl_keys \ sslserver.cer -keystore cacerts -storepass changeit
Sprawdź, czy certyfikat serwera jest zainstalowany, czy nie:
C: \ Program Files \ Java \ jdk1.8.0_191 \ jre \ lib \ security> keytool -list -keystore cacerts
możesz zobaczyć listę zainstalowanych certyfikatów:
więcej szczegółów: https://sachin4java.blogspot.com/2019/08/javasecuritycertcertificateexception-no.html
źródło
dodaj wpis hosta z adresem IP odpowiadającym CN w certyfikacie
CN = someSubdomain.someorganisation.com
teraz zaktualizuj adres IP nazwą CN, do której próbujesz uzyskać dostęp do adresu URL.
U mnie to zadziałało.
źródło
źródło
Jeśli masz certyfikat z zarówno CN, jak i alternatywnymi nazwami podmiotu (SAN), jeśli składasz żądanie w oparciu o zawartość CN, ta konkretna treść musi również znajdować się w sieci SAN, w przeciwnym razie błąd zakończy się niepowodzeniem.
W moim przypadku CN coś miało, SAN coś innego. Musiałem użyć adresu URL SAN, a potem działało dobrze.
źródło
Dodaj swój adres IP do pliku hosts, który znajduje się w folderze C: \ Windows \ System32 \ drivers \ etc. Dodaj również adres IP i nazwę domeny adresu IP. przykład: aaa.bbb.ccc.ddd [email protected]
źródło
Problem rozwiązałem w następujący sposób.
1. Tworzenie klasy. Klasa ma kilka pustych implementacji
2. Tworzenie metody
źródło