2012-09-24 4 views
2

SSLSocket을 통해 핸드 셰이크에 대한 인증서를 사용하는 먼 호스트에 연결 중입니다. 모든 인증 기관에서 기본 JVM 트러스트 스토어를 사용하지 않으므로 원격 호스트 인증서를 트러스트 스토어에 추가해야합니다.SSLSocket : 서버 인증서에 액세스하기 전에 핸드 셰이크를 수행해야하는 이유는 무엇입니까?

SSLSocket에서 신뢰해야하는 인증서를 어떻게 얻을 수 있습니까? 그것은 악수를 요구하는 것으로 보이는 SSLSession을 사용해야 할 필요가 있다고 생각됩니다. 왜 인증서를 검색 할 수 있도록 핸드 셰이크를 수행해야합니까?

사용 된 원격 호스트 인증서를 추출 할 수있는 도구가 있습니까?

답변

3

일반적으로 신뢰할 수있는 인증서를 SSLSocket에서 가져 오지 말고, 신뢰할 수있는 인증서의 참조로 독립적으로 얻은 구성 설정이어야합니다.

첫 번째 연결에 대한 인증서를 얻고, 그 연결이 도청되지 않기를 바란다. 그리고이 연결을 후속 연결에 대한 참조로 사용하십시오 (일반적으로 SSH로 수행되는 것과 유사합니다. 첫 번째 연결에서 서버 키의 지문을 반드시 알 필요는 없지만 나중에 동일한 지 확인하십시오).

보안상의 이유로 이것은 초기 연결이 MITM 공격자에 의해 가로 챌 수 있으므로 (이후의 모든 연결이 취약해질 수 있기 때문에) 이상적이지 않습니다.하지만 이는 확실히 위험을 완화하는 방법입니다. 이상적으로, 당신은 다른 방법으로 얻은 알려진 참조와 그 인증서를 비교해야합니다.

사용자 지정 X509TrustManager를 사용하여 핸드 셰이크 중에 원격 인증서에 액세스 할 수 있습니다 (또는 당신이 그것으로 신뢰 검증을 비활성화하고 나중에 인증서를 얻을 수 있습니다) 당신이 당신의 SSLSocketFactory을 얻을 수있는 당신이 다음 SSLContext을 초기화하는 데 사용할 수있는, . 트러스트 관리자에서 트러스트 확인을 사용하지 않는 것은 일반적으로 좋지 않지만 (MITM 공격에 대한 연결을 열었으므로)이 목적을 위해서는 받아 들일 수 있습니다. 더 많은 또는 더 적은 것을 수행해야하는 InstallCert 유틸리티에 관심이있을 수 있습니다.

인증서에 액세스하기 전에 왜 핸드 셰이크를 수행해야합니까?

SSL/TLS 소켓 API의 목적은 응용 프로그램 계층에 안전하다고 생각할 수있는 소켓을 제공하고 그 단계에서 보통 소켓으로 사용할 수 있기 때문입니다. 통상, JSSE (또는 일반적으로 다른 SSL/TLS 스택)의 대부분의 사용에서는, 그 스택을 사용하는 어플리케이션 개발자로서 명시 적으로 검증을 실시하고 싶지는 않습니다. 핸드 셰이크 중에 인증서를 확인하는 것은 또한 TLS specification의 일환으로 권장 :

서버 안녕하세요 완료 메시지를 수신하면

, 클라이언트는 를 필요한 경우 서버가 유효한 인증서를 한 것으로 확인하고 있는지 확인해야 server hello 매개 변수를 사용할 수 있습니다.

+1

마침내 문서에서 인증 기관이 내 트러스트 스토어에 추가됩니다. 그러나 때로는 설명서에서 찾을 수없는 경우도 있지만 원격 호스트 설명서에 명시 적으로 언급되지 않은 경우 해당 인증서를 검색하는 방법을 알고 싶을 수도 있습니다. 감사합니다 –

+1

+1 당신이 신뢰를 쌓아 가려고하는 연결을 통해 신뢰 자료를 수락하는 것은 말이되지 않습니다. 오프라인 프로세스 여야합니다. – EJP

4

실제로 인증서는 핸드 셰이크 중에 표시되므로 서버가 자신을 식별 할 수 있고 결국 클라이언트와 동일하게 식별 할 수 있습니다.

당신이 할 경우 :

SSLContext context = SSLContext.getInstance("TLS"); 
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
[...] 
SavingTrustManager tm = new SavingTrustManager(defaultTrustManager); 
SSLSocket socket = (SSLSocket)factory.createSocket(host, port); 
try { 
    socket.startHandshake(); 
    socket.close(); 
} catch (SSLException e) { 
    e.printStackTrace(System.out); 
} 

당신이 startHandshake()에서 예외가 발생하지 않는 경우, 그것은 인증서가 이미 신뢰할 수있는 기관의 서명의 몇 가지 이유 (키 스토어에 직접 존재하는, 신뢰할 의미).

예외가 발생하거나, 당신은 다운로드 체인에 액세스 할 수 없습니다 :를 X509Certificate 객체 인스턴스와 함께 K-ieth 스토어

X509Certificate[] chain = tm.chain; 
if (chain == null) { 
    // error in downloading certificate chain 
    return; 
} 

// loop through chain 
for (int i = 0; i < chain.length; i++) { 
    X509Certificate cert = chain[i]; 
    [....] 
} 

을, 당신이 실제로 업데이트 할 수 있습니다 다음에 대한

X509Certificate cert = chain[k]; 
String alias = host + "-" + (k + 1); 
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); 
[...] 
ks.setCertificateEntry(alias, cert); 
OutputStream out = new FileOutputStream("jssecacerts"); 
ks.store(out, passphrase); 
out.close(); 

here을 완전한 샘플.

또는 신뢰할 수있는 서버에 대한 인증서를 다운로드하는 또 다른, 어쩌면 더 안전한 방법은 openssl 명령어를 사용한다 :

# openssl s_client -showcerts -connect $SERVER:$PORT 2>&1 | \ 
     sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' >/tmp/$SERVERNAME.cert 

keytool와 함께 평소와 같이 가져옵니다.

+0

필자도 이런 종류의 것이 필요할 때'openssl s_client' 메소드가 더 빠르다는 것을 인정해야합니다. – Bruno

+0

그것은 내가 한 일이지만 실제 고통 : D –

+0

제공된 링크가 작동하지만 보이는 내용/전체 샘플이 없습니다. 전체 샘플을 게시 하시겠습니까? – sceiler

관련 문제