HTTPS를 통해 웹 서비스를 사용하는 Java 웹 서비스 클라이언트가 있습니다.
import javax.xml.ws.Service;
@WebServiceClient(name = "ISomeService", targetNamespace = "http://tempuri.org/", wsdlLocation = "...")
public class ISomeService
extends Service
{
public ISomeService() {
super(__getWsdlLocation(), ISOMESERVICE_QNAME);
}
서비스 URL ( https://AAA.BBB.CCC.DDD:9443/ISomeService
)에 연결할 때 예외가 발생 java.security.cert.CertificateException: No subject alternative names present
합니다.
이 문제를 해결하기 위해 먼저 openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt
파일을 실행 하고 다음 내용을 얻었습니다 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, 이제
- 과
certs.txt
사이 의 일부를 추출-----BEGIN CERTIFICATE-----
하고-----END CERTIFICATE-----
, - 인증서 이름이 같도록 수정
AAA.BBB.CCC.DDD
하고 - 그런 다음
keytool -importcert -file fileWithModifiedCertificate
(여기서는fileWithModifiedCertificate
작업 1과 2 의 결과)를 사용하여 결과를 가져옵니다 .
이 올바른지?
그렇다면 IP 기반 주소 ( AAA.BBB.CCC.DDD
) 에서 1 단계의 인증서를 정확히 어떻게 작동시킬 수 있습니까?
업데이트 1 (2013년 10월 23일 15시 37분 MSK는) : A와 답변에 비슷한 질문 , 나는 다음을 읽어
해당 서버를 제어하지 않는 경우 해당 호스트 이름을 사용합니다 (기존 인증서에 해당 호스트 이름과 일치하는 CN이 적어도있는 경우).
“사용”이란 정확히 무엇을 의미합니까?
답변
여기에 제시된 접근 방식을 사용하여 HTTPS 검사를 비활성화하여 문제를 해결했습니다 .
ISomeService
클래스 에 다음 코드를 넣었습니다 .
static {
disableSslVerification();
}
private static void disableSslVerification() {
try
{
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
}
https://AAA.BBB.CCC.DDD:9443/ISomeService
테스트 목적으로 만 사용하고 있기 때문에 충분한 솔루션입니다.
답변
나는 같은 문제를 가지고 있으며이 코드로 해결되었습니다. 웹 서비스를 처음 호출하기 전에이 코드를 넣었습니다.
javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
new javax.net.ssl.HostnameVerifier(){
public boolean verify(String hostname,
javax.net.ssl.SSLSession sslSession) {
return hostname.equals("localhost");
}
});
간단하고 잘 작동합니다.
다음 은 원본입니다.
답변
이것은 오래된 질문이지만 JDK 1.8.0_144에서 jdk 1.8.0_191로 이동할 때 동일한 문제가 발생했습니다.
변경 로그에서 힌트를 찾았습니다.
다음과 같은 추가 시스템 속성을 추가하여이 문제를 해결하는 데 도움이되었습니다.
-Dcom.sun.jndi.ldap.object.disableEndpointIdentification=true
답변
클라이언트가 요청하는 내용에 대해 인증서 ID 확인이 수행됩니다.
클라이언트가 https://xxx.xxx.xxx.xxx/something
(wherexxx.xxx.xxx.xxx
IP 주소)를 사용할 때이 IP 주소에 대해 인증서 ID를 확인합니다 (이론상 IP SAN 확장 만 사용).
인증서에 IP SAN이 없지만 DNS SAN (또는 DNS SAN이없는 경우 주체 DN의 공통 이름)이있는 경우 클라이언트가 해당 호스트 이름 (또는 호스트 이름 가능한 값이 여러 개인 경우 인증서가 유효합니다). 예를 들어 cert에에 대한 이름이있는 www.example.com
경우 https://www.example.com/something
.
물론 해당 IP 주소로 확인하려면 해당 호스트 이름이 필요합니다.
또한 DNS SAN이있는 경우 주제 DN의 CN이 무시되므로이 경우 DNS SAN 중 하나와 일치하는 이름을 사용하십시오.
답변
인증서를 가져 오려면 :
- 서버에서 인증서를 추출합니다. 예를 들어
openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt
PEM 형식으로 인증서를 추출합니다. - keytool이 예상하는 것과 같이 인증서를 DER 형식으로 변환하십시오.
openssl x509 -in certs.txt -out certs.der -outform DER
- 이제이 인증서를 시스템 기본 ‘cacert’파일로 가져 오려고합니다. Java 설치를위한 시스템 기본 ‘cacerts’파일을 찾습니다. 기본 Java 설치의 cacerts 위치를 얻는 방법을 살펴보십시오 .
- 해당 cacerts 파일로 인증서를 가져옵니다.
sudo keytool -importcert -file certs.der -keystore <path-to-cacerts>
기본 cacerts 암호는 ‘changeit’입니다.
인증서가 FQDN에 대해 발급되고 Java 코드의 IP 주소로 연결하려는 경우 인증서 자체를 엉망으로 만드는 대신 코드에서이 문제를 수정해야합니다. FQDN으로 연결하도록 코드를 변경하십시오. 개발 컴퓨터에서 FQDN을 확인할 수없는 경우 호스트 파일에 추가하거나이 FQDN을 확인할 수있는 DNS 서버로 컴퓨터를 구성합니다.
답변
다른 답변이 여기에서 제안하는 것과 달리 코드를 변경하거나 SSL을 비활성화하는 대신 인증서에 제목 대체 이름을 추가하여이 문제를 올바른 방법으로 해결했습니다. “제목 대체 이름이 없습니다”라는 예외가 명확하게 표시되면 올바른 방법으로 추가해야합니다.
단계별로 이해하려면 이 링크를 참조하십시오 .
위의 오류는 JKS 파일에 애플리케이션에 액세스하려는 필수 도메인이 없음을 의미합니다. 여러 도메인을 추가하려면 Open SSL 및 키 도구를 사용해야합니다.
- openssl.cnf를 현재 디렉토리에 복사합니다.
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/emailAddress=postmaster@example.com' -days 365
-
공개 키 (.pem) 파일을 PKS12 형식으로 내 보냅니다. 암호를 입력하라는 메시지가 표시됩니다.
openssl pkcs12 -export -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -export -in self-signed.pem -inkey private.key -name myalias -out keystore.p12
-
자체 서명 된 PEM (Keystore)에서 a.JKS 만들기
keytool -importkeystore -destkeystore keystore.jks -deststoretype PKCS12 -srcstoretype PKCS12 -srckeystore keystore.p12
-
위의 키 저장소 또는 JKS 파일에서 인증서 생성
keytool -export -keystore keystore.jks -alias myalias -file selfsigned.crt
-
위의 인증서는 자체 서명되고 CA에 의해 검증되지 않았으므로 Truststore에 추가해야합니다 (MAC의 경우 아래 위치에있는 Cacerts 파일, Windows의 경우 JDK가 설치된 위치를 확인하십시오.)
sudo keytool -importcert -file selfsigned.crt -alias myalias -keystore /Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/security/cacerts
답변
모든 SSL 검증을 비활성화하고 싶지 않을 수 있으므로 대안보다 약간 덜 무서운 이것을 통해 hostName 검증을 비활성화 할 수 있습니다.
HttpsURLConnection.setDefaultHostnameVerifier(
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
[편집하다]
conapart3에서 언급했듯이 SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
이제는 더 이상 사용되지 않으므로 이후 버전에서 제거 될 수 있으므로 모든 확인이 해제 된 솔루션은 피할 것이라고 말하지만 나중에 직접 롤링해야 할 수도 있습니다.