éçºä¸ã®ãã¹ãç°å¢ã¨ãã§ããããããã¿ï¼çãªã
Apache HttpComponentsï¼Clientã使ã£ã¦ãSSLèªå·±ç½²åè¨¼ææ¸ã使ã£ã¦éä¿¡ãããããã¹ãåã®æ¤è¨¼ãç¡å¹åããæ¹æ³ã«ã¤ãã¦ãã¡ã¢ã¨ãã¦æ¸ãã¦ããã¾ãã
Apache HttpComponents – Apache HttpComponents
ãã¤ãå¾®å¦ã«ããæ¹ãå¿ãã¦ãæ¯åº¦æ¯åº¦èª¿ã¹ããã¨ã«ãªã£ã¦ããã®ã§ãåå¿é²çã«ã¨ã
ãã¡ããããå©ç¨ã¯ãã¹ããªã©ã§ã®ç¯å²ã§ãã§ããã
ã¡ãªã¿ã«ãjava.net.URLConnectionã使ãå ´åã«ã¤ãã¦ã¯ã以忏ãã¾ããã
JavaでSSL証明書の検証無効化、ホスト名検証の無効化…とデバッグ - CLOVER
æºå
Apache HttpComponentsã£ã¦ããã¼ã¸ã§ã³ã§ãã£ããã³ãã³ãAPIãå¤ããã®ã§ããããï¼ãã¨ããã®ã¯è¨ãã¥ããã®ã§ãããä»åã¯Apache HttpComponentsï¼ã¨ãããClientï¼ã®4.5.1ã対象ã«ãã¾ãã
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.1</version> </dependency>
ãã¹ãã³ã¼ãã«ã¯ãJUnitï¼AssertJãå©ç¨ã
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> <version>3.2.0</version> <scope>test</scope> </dependency>
ã¾ãããã¹ãç¨ã®SSLãæå¹ã«ããWebãµã¼ãã¼ã¯ãUbuntu Linuxã§ã¤ã³ã¹ãã¼ã«ã§ããSSLãæå¹ã«ããApacheã¨ãã¾ããã
ãµã³ãã«ã³ã¼ãã§ä½¿ãimportæ
以éã®ãµã³ãã«ã³ã¼ãã§ã¯ã以ä¸ã®importæããããã¨ãåæã«ãã¦ãã¾ãã
import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLPeerUnverifiedException; import org.apache.http.HttpStatus; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContexts; import org.apache.http.ssl.TrustStrategy; import org.apache.http.util.EntityUtils; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy;
ã§ã¯ã§ã¯ãæ¸ãã¦ãã£ã¦ã¿ã¾ãã
äºè±¡ãã®1ãèªå·±ç½²åè¨¼ææ¸ãªã®ã§ã¨ã©ã¼ã«ãªã
éä¿¡æã«ããããªã¹ã¿ãã¯ãã¬ã¼ã¹ãåºåããããããªã±ã¼ã¹ã
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509) at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216) at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979) at sun.security.ssl.Handshaker.process_record(Handshaker.java:914) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
SSLè¨¼ææ¸ã®æ¤è¨¼ã§ãNGã¨ãªãå ´åã§ãããèªå·±ç½²åè¨¼ææ¸ã ã¨ãããã«ééããã¨æãã¾ãã
ãã¹ãã³ã¼ãã¯ããããªæãã
@Test public void testSelfSignedFailure() throws IOException { try (CloseableHttpClient client = HttpClients.createDefault()) { HttpGet get = new HttpGet("https://localhost"); assertThatThrownBy(() -> { try (CloseableHttpResponse response = client.execute(get)) { assertThat(response.getStatusLine().getStatusCode()) .isEqualTo(HttpStatus.SC_OK); assertThat(EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8)) .contains("apache2"); } }) .isInstanceOf(SSLHandshakeException.class) .hasMessageContaining("sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target"); } }
èªå·±ç½²åè¨¼ææ¸ã§ãOKã«ããã«ã¯
ããããã¹ããã«ã¯ã以ä¸ã®ãããªã³ã¼ããæ¸ãã¦SSLContextã使ãã¾ãã
TrustStrategy trustStrategy = new TrustSelfSignedStrategy();
SSLContext sslContext =
SSLContexts
.custom()
.loadTrustMaterial(trustStrategy)
.build();
TrustStrategyã®å®è£ ã§ãããTrustSelfSignedStrategyã使ç¨ãããã¨ã§èªå·±ç½²åè¨¼ææ¸ã§ãOKã«ãªãã¾ãããã¨ã
ã§ããã¡ãã使ã£ã¦HttpClientã使ãããã¨ã
try (CloseableHttpClient client = HttpClients .custom() .setSSLContext(sslContext) .build()) { HttpGet get = new HttpGet("https://localhost");
ããã§ãè¨¼ææ¸ã®ã¨ã©ã¼ã¯åé¿ã§ãã¾ãã
äºè±¡ãã®2ããã¹ãåã®æ¤è¨¼ã§ã¨ã©ã¼ã«ãªã
ããã ãã§ã¯ã¾ã ã¨ã©ã¼ã«ãªãå ´åããSSLè¨¼ææ¸ã«æ¸ããã¦ãããã¹ãåããå®éã«ã¢ã¯ã»ã¹ãã¦ãããã¹ãã¨åããªãå ´åã
ãã®ã±ã¼ã¹ã ã¨ããã®ãããªã¹ã¿ãã¯ãã¬ã¼ã¹ãå¾ããã¾ãã
javax.net.ssl.SSLPeerUnverifiedException: Host name 'localhost' does not match the certificate subject provided by the peer (CN=e611e15f9c9d) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.verifyHostname(SSLConnectionSocketFactory.java:465) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:395) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:353) at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:134) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353) at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184) at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
å ã»ã©ã®SSLè¨¼ææ¸ã®æ¤è¨¼ãè¡ããªãã ãã®ã³ã¼ãã¯ããã®ãããªæãã«ãªã£ã¦ãã¾ãã
@Test public void testHostNameFailure() throws IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException { TrustStrategy trustStrategy = new TrustSelfSignedStrategy(); SSLContext sslContext = SSLContexts .custom() .loadTrustMaterial(trustStrategy) .build(); assertThatThrownBy(() -> { try (CloseableHttpClient client = HttpClients .custom() .setSSLContext(sslContext) .build()) { HttpGet get = new HttpGet("https://localhost"); try (CloseableHttpResponse response = client.execute(get)) { assertThat(response.getStatusLine().getStatusCode()) .isEqualTo(HttpStatus.SC_OK); assertThat(EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8)) .contains("apache2"); } } }) .isInstanceOf(SSLPeerUnverifiedException.class) .hasMessageContaining("Host name 'localhost' does not match the certificate subject provided by the peer (CN=e611e15f9c9d)"); }
ããããã ã¨ä»åç¨æããç°å¢ã§ã¯ããã¹ãåãè¨¼ææ¸ã¨ã¢ã¯ã»ã¹ãã¹ã§ä¸ä¸è´ã®ãããã¨ã©ã¼ã«ãªãã¨ã
ããã§ãããã§ã¯HostnameVerifierã使ç¨ãã¾ãã
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
NoopHostnameVerifierã使ç¨ããã¨ããã¹ãåã®æ¤è¨¼ãç¡å¹åã§ãã¾ãã
SSLè¨¼ææ¸ã®æ¤è¨¼ã¨ããã¹ãåã®æ¤è¨¼ãå ¨é¨åãããã³ã¼ãã¯ããã®ãããªå½¢ã«ãªãã¾ãã
@Test public void testSelfSignedSuccess() throws IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException { TrustStrategy trustStrategy = new TrustSelfSignedStrategy(); SSLContext sslContext = SSLContexts .custom() .loadTrustMaterial(trustStrategy) .build(); HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE; try (CloseableHttpClient client = HttpClients .custom() .setSSLContext(sslContext) .setSSLHostnameVerifier(hostnameVerifier) .build()) { HttpGet get = new HttpGet("https://localhost"); try (CloseableHttpResponse response = client.execute(get)) { assertThat(response.getStatusLine().getStatusCode()) .isEqualTo(HttpStatus.SC_OK); assertThat(EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8)) .contains("apache2"); } } }
HostnameVerifierã¯ãsetSSLHostnameVerifierã§æå®ãã¾ãã
try (CloseableHttpClient client =
HttpClients
.custom()
.setSSLContext(sslContext)
.setSSLHostnameVerifier(hostnameVerifier)
.build()) {
ã¨ãããããç®çã¯éæã§ãã¾ãããã£ã¨ã
å¥è§£
SSLContextã¨SSLConnectionSocketFactoryã®çµã¿åããã§ããåæ§ã®ãã¨ãå®ç¾ã§ãã¾ãã
@Test public void testSelfSignedSuccessAnother() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException, IOException { TrustStrategy trustStrategy = new TrustSelfSignedStrategy(); SSLContext sslContext = SSLContexts .custom() .loadTrustMaterial(trustStrategy) .build(); HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE; SSLConnectionSocketFactory sslConnSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); try (CloseableHttpClient client = HttpClients .custom() .setSSLSocketFactory(sslConnSocketFactory) .build()) { HttpGet get = new HttpGet("https://localhost"); try (CloseableHttpResponse response = client.execute(get)) { assertThat(response.getStatusLine().getStatusCode()) .isEqualTo(HttpStatus.SC_OK); assertThat(EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8)) .contains("apache2"); } } }
ãã®å ´åã¯ãsetSSLSocketFactoryã使ç¨ãã¾ãã
try (CloseableHttpClient client =
HttpClients
.custom()
.setSSLSocketFactory(sslConnSocketFactory)
.build()) {
以ä¸ã§ããã¼ã
åèï¼
JSSE_Fortify_SCA_Rules/ApacheHTTPClientFluentExample.java at master · GDSSecurity/JSSE_Fortify_SCA_Rules · GitHub
How do you create SSL socket factory in new Apache Http Client 4.3? - Stack Overflow