SSL 핸드쉐이크 경고: Java 1.7.0으로 업그레이드한 후 인식되지 않는_name 오류
저는 오늘 자바 1.6에서 자바 1.7로 업그레이드했습니다.그 후 SSL 경유로 웹 서버에 접속하려고 하면 다음 오류가 발생합니다.
javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name
at sun.security.ssl.ClientHandshaker.handshakeAlert(ClientHandshaker.java:1288)
at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1904)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1027)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1262)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1289)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1273)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:523)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1296)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
at java.net.URL.openStream(URL.java:1035)
코드는 다음과 같습니다.
SAXBuilder builder = new SAXBuilder();
Document document = null;
try {
url = new URL(https://some url);
document = (Document) builder.build(url.openStream());
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(DownloadLoadiciousComputer.class.getName()).log(Level.SEVERE, null, ex);
}
테스트 프로젝트이기 때문에 다음 코드와 함께 신뢰할 수 없는 인증서를 허용하고 사용합니다.
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
Logger.getLogger(DownloadManager.class.getName()).log(Level.SEVERE, null, e);
}
https://google.com 접속에 성공했습니다.내 잘못은 어디에 있지?
고마워요.
Java 7에서는 SNI 지원이 도입되었습니다.이것은 디폴트로 유효하게 되어 있습니다.SSL 핸드쉐이크로 잘못 구성된 특정 서버가 "인식할 수 없는 이름" 경고를 보내 대부분의 클라이언트에서 무시한다는 것을 알게 되었습니다.자바 제외@Bob Kerns가 언급했듯이 Oracle 엔지니어는 이 오류/기능을 수정하기를 거부합니다.
하려면 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,jsse.enableSNIExtension
을 다시과 같이합니다.프로그램을 다시 컴파일하지 않고 작동시키려면 다음과 같이 프로그램을 실행하십시오.
java -Djsse.enableSNIExtension=false yourClass
속성은 Java 코드에서도 설정할 수 있지만 SSL 작업 전에 설정해야 합니다.SSL 라이브러리가 로드되면 속성을 변경할 수 있지만 SNI 상태에는 영향을 주지 않습니다.런타임에 SNI를 디세블로 하려면(상기 제한사항 포함) 다음과 같이 사용합니다.
System.setProperty("jsse.enableSNIExtension", "false");
이 플래그를 설정하면 응용 프로그램에서 SNI가 비활성화된다는 단점이 있습니다.SNI 를 사용하고, 설정이 잘못된 서버를 서포트하려면 , 다음의 순서에 따릅니다.
- 작성하다
SSLSocket
연결할 호스트 이름을 지정합니다. 이름을 붙입시다sslsock
. - 보세요.
sslsock.startHandshake()
이 경우 완료될 때까지 차단되거나 오류가 발생할 경우 예외가 발생합니다.가startHandshake()
예외 메시지를 받습니다.와 같다면handshake alert: unrecognized_name
잘못 설정된 서버를 발견했습니다. unrecognized_name
Java에서는 ), a warning(Java의 ), retry opening(재시도 retry opening(Java의 경우)SSLSocket
그러나 이번에는 호스트 이름이 없습니다.이것에 의해, SNI 는 사실상 디세블이 됩니다(결국, SNI 확장은 ClientHello 메시지에 호스트명을 추가하는 것입니다).
Webscarab SSL 프록시의 경우 이 커밋은 폴백 설정을 구현합니다.
나도 같은 문제를 가지고 있었다.호스트의 ServerName 또는 ServerAlias를 포함하도록 Apache 구성을 조정해야 했습니다.
이 코드는 실패했습니다.
public class a {
public static void main(String [] a) throws Exception {
java.net.URLConnection c = new java.net.URL("https://mydomain.com/").openConnection();
c.setDoOutput(true);
c.getOutputStream();
}
}
그리고 이 코드가 작동했습니다.
public class a {
public static void main(String [] a) throws Exception {
java.net.URLConnection c = new java.net.URL("https://google.com/").openConnection();
c.setDoOutput(true);
c.getOutputStream();
}
}
Wireshark는 TSL/SSL Hello 중에 경고(레벨: 경고, 설명:인식할 수 없는 이름) 서버 Hello가 서버에서 클라이언트로 전송되었습니다.그러나 Java 7.1은 경고에 불과했지만 즉시 "Fatal, Description:예기치 않은 메시지"는 Java SSL 라이브러리가 인식할 수 없는 이름의 경고를 보고 싶어하지 않는다는 것을 의미합니다.
Wiki on Transport Layer Security(TLS)에서 다음을 수행합니다.
112 인식할 수 없는 이름 경고 TLS만. 클라이언트의 서버 이름 표시기가 서버에서 지원되지 않는 호스트 이름을 지정했습니다.
이를 통해 Apache 설정 파일을 살펴보니 클라이언트/자바 측에서 전송된 이름에 ServerName 또는 ServerAlias를 추가해도 오류 없이 정상적으로 동작하는 것을 알 수 있었습니다.
<VirtualHost mydomain.com:443>
ServerName mydomain.com
ServerAlias www.mydomain.com
System 속성 jse.enable을 사용하여 SNI 레코드 전송을 비활성화할 수 있습니다.SNIExtension=false.
할 수 는, 「 」를 하는 것이 도움이 됩니다.SSLCocketFactory#createSocket()
(호스트 파라미터가 없거나 소켓이 연결되어 있습니다.server_name __ 、 server _ name 표표____ 。
새로운 Apache 서버 빌드에서도 이 오류가 발생했습니다.
은 '어느 쪽인가'를 이었습니다.ServerAlias
httpd.conf
Java가 접속하려고 하는 호스트명에 대응하고 있습니다. ★★★★★★★★★★★★★★★★★★ServerName
이치노SSL 증명서는 외부 호스트명을 사용하고 있었지만, 경고를 회피하기에는 불충분했습니다.
디버깅을 용이하게 하려면 다음 ssl 명령을 사용합니다.
openssl s_client -servername <hostname> -connect <hostname>:443 -state
그 호스트명에 문제가 있는 경우는, 출력의 상부에 다음의 메세지가 표시됩니다.
SSL3 alert read: warning:unrecognized name
또, 그 커맨드를 사용해 내부 호스트명에 접속했을 때에, SSL 증명서와 일치하지 않는 에러는 발생하지 않았던 것에 주의해 주세요.
Apache의 기본 가상 호스트 메커니즘에 의존하는 대신 임의의 ServerName 및 와일드카드 ServerAlias를 사용하는 마지막 캐치올 가상 호스트를 정의할 수 있습니다.
ServerName catchall.mydomain.com
ServerAlias *.mydomain.com
이렇게 하면 SNI를 사용할 수 있으며 Apache는 SSL 경고를 반환하지 않습니다.
물론 이것은 와일드카드 구문을 사용하여 모든 도메인을 쉽게 설명할 수 있는 경우에만 작동합니다.
도움이 될 거예요.Apache HttpClient 4.4에서 SNI 오류를 재시도하려면 다음과 같이 하십시오(HTTPCLIENT-1522 참조).
public class SniHttpClientConnectionOperator extends DefaultHttpClientConnectionOperator {
public SniHttpClientConnectionOperator(Lookup<ConnectionSocketFactory> socketFactoryRegistry) {
super(socketFactoryRegistry, null, null);
}
@Override
public void connect(
final ManagedHttpClientConnection conn,
final HttpHost host,
final InetSocketAddress localAddress,
final int connectTimeout,
final SocketConfig socketConfig,
final HttpContext context) throws IOException {
try {
super.connect(conn, host, localAddress, connectTimeout, socketConfig, context);
} catch (SSLProtocolException e) {
Boolean enableSniValue = (Boolean) context.getAttribute(SniSSLSocketFactory.ENABLE_SNI);
boolean enableSni = enableSniValue == null || enableSniValue;
if (enableSni && e.getMessage() != null && e.getMessage().equals("handshake alert: unrecognized_name")) {
TimesLoggers.httpworker.warn("Server received saw wrong SNI host, retrying without SNI");
context.setAttribute(SniSSLSocketFactory.ENABLE_SNI, false);
super.connect(conn, host, localAddress, connectTimeout, socketConfig, context);
} else {
throw e;
}
}
}
}
그리고.
public class SniSSLSocketFactory extends SSLConnectionSocketFactory {
public static final String ENABLE_SNI = "__enable_sni__";
/*
* Implement any constructor you need for your particular application -
* SSLConnectionSocketFactory has many variants
*/
public SniSSLSocketFactory(final SSLContext sslContext, final HostnameVerifier verifier) {
super(sslContext, verifier);
}
@Override
public Socket createLayeredSocket(
final Socket socket,
final String target,
final int port,
final HttpContext context) throws IOException {
Boolean enableSniValue = (Boolean) context.getAttribute(ENABLE_SNI);
boolean enableSni = enableSniValue == null || enableSniValue;
return super.createLayeredSocket(socket, enableSni ? target : "", port, context);
}
}
그리고.
cm = new PoolingHttpClientConnectionManager(new SniHttpClientConnectionOperator(socketFactoryRegistry), null, -1, TimeUnit.MILLISECONDS);
용도:
- System.setProperty("jse.enable")SNIExtension", "false";
- Tomcat을 재시작합니다(중요).
스프링 부트 및 jvm 1.7 및 1.8에서 이 문제가 발생.AWS에서는 ServerName과 ServerAlias를 일치하도록 변경할 수 있는 옵션이 없었기 때문에 다음 작업을 수행했습니다.
build.gradle에는 다음 항목이 추가되었습니다.
System.setProperty("jsse.enableSNIExtension", "false")
bootRun.systemProperties = System.properties
그 때문에, 「인식할 수 없는 이름」의 문제를 회피할 수 있었습니다.
안타깝게도 jarsigner.exe 도구에는 시스템 속성을 제공할 수 없습니다.
@eckes의 결함 7127374를 참고하여 결함 7177232를 제출하여 실수로 닫힌 이유를 설명하였습니다.
저의 결함은 jarsigner 툴에 대한 영향에 관한 것이지만, 다른 결함을 다시 열어 적절히 대처하는 것으로 이어질 수 있습니다.
업데이트: 실제로 Jarsigner 도구에 시스템 속성을 제공할 수 있지만 도움말 메시지에는 표시되지 않습니다.사용하다jarsigner -J-Djsse.enableSNIExtension=false
같은 문제에 부딪혔는데, 리버스 DNS가 올바르게 설정되어 있지 않은 것이 판명되어 IP의 호스트명이 잘못되어 있습니다.리버스 DNS를 수정하고httpd를 재기동하면 경고가 사라집니다.(리버스 DNS를 수정하지 않으면 ServerName을 추가해도 문제가 되지 않습니다.)
★★★VirtualHost
의 »ServerName
는 디폴트로 코멘트 아웃 되어 있습니다.언코멘트 후에 효과가 있었다.
Resttemplate를 사용하여 클라이언트를 구축하는 경우 엔드포인트를 https://IP/path_to_service와 requestFactory로만 설정할 수 있습니다.
Apache를 .「 」 、 「 Tomcat 」 、 「 Apache 」
public static HttpComponentsClientHttpRequestFactory requestFactory(CloseableHttpClient httpClient) {
TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
};
SSLContext sslContext = null;
try {
sslContext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
final SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext,hostnameVerifier);
final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", new PlainConnectionSocketFactory())
.register("https", csf)
.build();
final PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
cm.setMaxTotal(100);
httpClient = HttpClients.custom()
.setSSLSocketFactory(csf)
.setConnectionManager(cm)
.build();
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
return requestFactory;
}
Java 1.6_29에서 1.7로 업그레이드 할 때도 이 문제가 발생하였습니다.
놀랍게도, 제 고객은 Java 제어판에서 이 문제를 해결할 수 있는 설정을 발견했습니다.
고급 탭에서 'SSL 2.0 호환 ClientHello 형식 사용'을 선택할 수 있습니다.
이것으로 문제가 해결된 것 같습니다.
Internet Explorer 브라우저에서 Java 애플릿을 사용하고 있습니다.
이게 도움이 됐으면 좋겠다.
Appache httpclient 4.5.11을 사용합니다..*.hostname.com
되었지만 속성에 하지 않습니다.System.setProperty("jsse.enableSNIExtension", "false");
구글 위치 클라이언트에서 오류가 발생했기 때문입니다.
간단한 솔루션을 찾았습니다(소켓만 수정).
import io.micronaut.context.annotation.Bean;
import io.micronaut.context.annotation.Factory;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import javax.inject.Named;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.util.List;
@Factory
public class BeanFactory {
@Bean
@Named("without_verify")
public HttpClient provideHttpClient() {
SSLConnectionSocketFactory connectionSocketFactory = new SSLConnectionSocketFactory(SSLContexts.createDefault(), NoopHostnameVerifier.INSTANCE) {
@Override
protected void prepareSocket(SSLSocket socket) throws IOException {
SSLParameters parameters = socket.getSSLParameters();
parameters.setServerNames(List.of());
socket.setSSLParameters(parameters);
super.prepareSocket(socket);
}
};
return HttpClients.custom()
.setSSLSocketFactory(connectionSocketFactory)
.build();
}
}
Ubuntu Linux 서버에서 Eclipse를 통해 액세스할 때 하위 버전을 실행하는 것과 같은 문제가 발생했습니다.
Apache를 다시 시작할 때 발생하는 경고와 관련된 문제인 것으로 나타났습니다.
[Mon Jun 30 22:27:10 2014] [warn] NameVirtualHost *:80 has no VirtualHosts
... waiting [Mon Jun 30 22:27:11 2014] [warn] NameVirtualHost *:80 has no VirtualHosts
이것은, 에서의 새로운 엔트리에 의한 것입니다.ports.conf
곳에, , , , , , ,NameVirtualHost
입력되었습니다.sites-enabled/000-default
.
의 한 후ports.conf
(Apache를 재기동한 후 자연스럽게 문제가 해소되었습니다.
여기에 솔루션을 추가합니다.이는 LAMP 사용자에게 도움이 될 수 있습니다.
Options +FollowSymLinks -SymLinksIfOwnerMatch
가상 호스트 구성에서 위의 행이 원인입니다.
오류 발생 시 가상 호스트 구성
<VirtualHost *:80>
DocumentRoot /var/www/html/load/web
ServerName dev.load.com
<Directory "/var/www/html/load/web">
Options +FollowSymLinks -SymLinksIfOwnerMatch
AllowOverride All
Require all granted
Order Allow,Deny
Allow from All
</Directory>
RewriteEngine on
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [NC,R=301,L]
</VirtualHost>
작업 구성
<VirtualHost *:80>
DocumentRoot /var/www/html/load/web
ServerName dev.load.com
<Directory "/var/www/html/load/web">
AllowOverride All
Options All
Order Allow,Deny
Allow from All
</Directory>
# To allow authorization header
RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
# RewriteCond %{SERVER_PORT} !^443$
# RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [NC,R=301,L]
</VirtualHost>
독자적인 HostnameVerifier 를 사용해 특정 접속을 암묵적으로 신뢰하는 간단한 방법이 있습니다.이 문제는 Java 1.7에서 SNI 확장이 추가된 경우에 발생하며, 오류는 서버 설정 오류로 인해 발생합니다.
"-Djse.enable"을 사용할 수 있습니다.SNIExtension=false"를 클릭하여 JVM 전체에서 SNI를 비활성화하거나 URL 연결 위에 커스텀 검증기를 구현하는 방법에 대해 설명하는 블로그를 읽습니다.
언급URL : https://stackoverflow.com/questions/7615645/ssl-handshake-alert-unrecognized-name-error-since-upgrade-to-java-1-7-0
'programing' 카테고리의 다른 글
nuxt 프로젝트에 store/index.js 파일이 없습니다. (0) | 2022.07.13 |
---|---|
일상적인 기계는 어떻게 프로그램됩니까? (0) | 2022.07.13 |
복제된 라우터 링크는 자 라우터 뷰에 로드되어야 하지만 메인 라우터 뷰도 새로고침됩니다. (0) | 2022.07.13 |
nuxt vuex에서 정의되지 않은 커밋 (0) | 2022.07.13 |
v-model 특성을 확인란에 추가하면 모두 확인 작업이 중지됨 (0) | 2022.07.13 |