문제

모듈을 추가하는 우리의 큰 Java 응용 프로그램을 대화와 함께 다른 회사의 SSL 보안 웹사이트입니다.문제는 사용하는 사이트는 자체 서명된 인증서입니다.나는 증명서의 사본을 확인하는 내가 발생하지 않는 man-in-the-middle 공격,그리고 나는 통합해야 하는 이 인증서는 우리의 코드에서는 방식으로 서버와의 연결을 성공적으로 될 것입니다.

여기에서의 기본 코드:

void sendRequest(String dataPacket) {
  String urlStr = "https://host.example.com/";
  URL url = new URL(urlStr);
  HttpURLConnection conn = (HttpURLConnection)url.openConnection();
  conn.setMethod("POST");
  conn.setRequestProperty("Content-Length", data.length());
  conn.setDoOutput(true);
  OutputStreamWriter o = new OutputStreamWriter(conn.getOutputStream());
  o.write(data);
  o.flush();
}

없이 추가적인 취급 장소에 대한 자체 서명된 인증서,이것에서 사망 나타납니다.getOutputStream()다음과 같은 경우를 제외하고:

Exception in thread "main" 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
....
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
....
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

이상적으로는 나의 코드를 가르치는 자바를 받아들이는 자체 서명된 인증서,이를 위해 한 자리에서 응용 프로그램,그리고 어디에도 없습니다.

나는 내가 가져올 수 있습으로 인증서를 JRE 의 인증 기관장,그리고할 수 있는 자바를 받아들입니다.하지 않는 방식을 가지고 싶다면 내가 도움이 될 수 있습;그것은 매우 침해에서 우리의 모든 고객의 컴퓨터를 하나의 모듈을 사용할 수 없습;에 영향을 미치는 모든 다른 Java 응용 프로그램을 사용하여 동일한 JRE,그리고 내가 좋아하지 않도록 확률의 다른 Java 응용 프로그램 혹시 이 사이트에 액세스하는 전무합니다.그것도 아닌 사소한 작업:유닉스에서 나에 대한 액세스 권한을 얻을 수정할 수 있는 권한이 JRE 에서 이 방법입니다.

나 또한 볼 수 있는 나를 만들 수 있습 TrustManager 인스턴스는 일부 사용자 정의 검사입니다.그것은 다음과 같이 나도를 만들 수 있 TrustManager 는 대리자가 실제 TrustManager 모든 경우에서를 제외하고 이 인증서입니다.하지만 그것처럼 보이는 TrustManager 설치 전 세계적으로,그리고 나는 생각에 영향을 미칠 것 다른 모든 연결에서의 응용 프로그램,그리고 냄새가 나지 않는 아주 나에게 맞는다.

무엇을 원하는 표준 또는 최고의 방법을 설정 Java 응용 프로그램을 받아들이는 자체 서명된 인증서입니까?할 수 있는 내가 달성하는 목표를 모두가 마음에,또는 나는 타협?이 있는 옵션을 포함하는 파일과 디렉터리와 구성 설정과 작은 코드?

도움이 되었습니까?

해결책

생성 SSLSocket 공장 직접 공장에 설정하십시오 HttpsURLConnection 연결하기 전에.

...
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(sslFactory);
conn.setMethod("POST");
...

당신은 하나를 만들고 싶을 것입니다 SSLSocketFactory 그리고 주위에 보관하십시오. 다음은 초기화하는 방법에 대한 스케치입니다.

/* Load the keyStore that includes self-signed cert as a "trusted" entry. */
KeyStore keyStore = ... 
TrustManagerFactory tmf = 
  TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, tmf.getTrustManagers(), null);
sslFactory = ctx.getSocketFactory();

키 스토어를 만드는 데 도움이 필요하면 의견을 제시하십시오.


키 스토어로드의 예는 다음과 같습니다.

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(trustStore, trustStorePassword);
trustStore.close();

PEM 형식 인증서로 키 스토어를 만들려면 사용하여 자신의 코드를 작성할 수 있습니다. CertificateFactory, 또는 그냥 가져 오십시오 keytool JDK (KeyTool 습관 "키 입력"을 위해 일하지만 "신뢰할 수있는 항목"에 적합합니다).

keytool -import -file selfsigned.pem -alias server -keystore server.jks

다른 팁

나는이 것을 해결하기 위해 온라인으로 많은 장소를 읽었습니다. 이것은 내가 작동하도록하기 위해 쓴 코드입니다.

                ByteArrayInputStream derInputStream = new ByteArrayInputStream(app.certificateString.getBytes());
                CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
                X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(derInputStream);
                String alias = "alias";//cert.getSubjectX500Principal().getName();

                KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
                trustStore.load(null);
                trustStore.setCertificateEntry(alias, cert);
                KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
                kmf.init(trustStore, null);
                KeyManager[] keyManagers = kmf.getKeyManagers();

                TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
                tmf.init(trustStore);
                TrustManager[] trustManagers = tmf.getTrustManagers();

                SSLContext sslContext = SSLContext.getInstance("TLS");
                sslContext.init(keyManagers, trustManagers, null);
                URL url = new URL(someURL);
                conn = (HttpsURLConnection) url.openConnection();
                conn.setSSLSocketFactory(sslContext.getSocketFactory());

app.certificatestring은 인증서가 포함 된 문자열입니다.

            static public String certificateString=
            "-----BEGIN CERTIFICATE-----\n" +
            "MIIGQTCCBSmgAwIBAgIHBcg1dAivUzANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UE" +
            "BhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsTIlNlY3VyZSBE" +
            ... a bunch of characters...
            "5126sfeEJMRV4Fl2E5W1gDHoOd6V==\n" +
            "-----END CERTIFICATE-----";

정확한 구조를 위의 정확한 구조를 유지하는 한 자체 서명 된 경우 인증서 문자열에 문자를 넣을 수 있음을 테스트했습니다. 노트북의 터미널 명령 줄을 사용하여 인증서 문자열을 얻었습니다.

a를 만드는 경우 SSLSocketFactory 옵션이 아니며 키를 JVM으로 가져 오십시오.

  1. 공개 키 검색 :$openssl s_client -connect dev-server:443, 그런 다음 파일을 만듭니다 dev-server.pem 그것은 보인다

    -----BEGIN CERTIFICATE----- 
    lklkkkllklklklklllkllklkl
    lklkkkllklklklklllkllklkl
    lklkkkllklk....
    -----END CERTIFICATE-----
    
  2. 키 가져 오기 : #keytool -import -alias dev-server -keystore $JAVA_HOME/jre/lib/security/cacerts -file dev-server.pem. 비밀번호: 변경

  3. JVM을 다시 시작합니다

원천: javax.net.ssl.sslhandshakeexception을 해결하는 방법?

우리는 복사 JRE 의 신뢰 저장소에 추가 우리 사용자 지정 인증서를 신뢰 저장소,다음 응용 프로그램을 사용하는 사용자 정의 신뢰 저장소와 시스템을 제공합니다.이 방법은 우리가 기본 JRE 신뢰 저장소 혼자입니다.

단점은 경우 업데이트 JRE 얻을 수 없는 새로운 신뢰 저장소가 자동으로 병합으로 사용자 정의 하나입니다.

당신은 아마 이러한 시나리오를 필요에 의해 설치하거나 시작 일상적인 확인하는 신뢰 저장소/jdk 및 확인에 대한 불일치 또는 자동 업데이트를 신뢰 저장소.I don't know what 발생한 경우 업데이트 신뢰 저장소 응용 프로그램이 실행되는 동안.

이 솔루션은 없 100%우아하거나 고장이지만,간단한 작동,그리고 필요 없는 코드입니다.

Commons-HTTPClient를 사용하여 자체 서명 된 인증서로 내부 HTTPS 서버에 액세스 할 때 이와 같은 작업을 수행해야했습니다. 예, 우리의 솔루션은 단순히 모든 것을 전달한 사용자 정의 신탁 관리자를 만드는 것이 었습니다 (디버그 메시지 로그).

이것은 로컬 SSLContext에서 SSL 소켓을 생성하는 자체 SSLSocketFactory를 갖추고 있습니다. Keystore/Certstore 근처에 전혀 갈 필요가 없습니다.

그래서 이것은 우리 지역의 SlSocketFactory에 있습니다.

static {
    try {
        SSL_CONTEXT = SSLContext.getInstance("SSL");
        SSL_CONTEXT.init(null, new TrustManager[] { new LocalSSLTrustManager() }, null);
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException("Unable to initialise SSL context", e);
    } catch (KeyManagementException e) {
        throw new RuntimeException("Unable to initialise SSL context", e);
    }
}

public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
    LOG.trace("createSocket(host => {}, port => {})", new Object[] { host, new Integer(port) });

    return SSL_CONTEXT.getSocketFactory().createSocket(host, port);
}

SecureProtocolsocketFactory를 구현하는 다른 방법과 함께. LOCALSSLTRUSTMANAGER는 위에서 언급 한 더미 신탁 관리자 구현입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top