안녕하세요, PSJ입니다.
오늘은 업무 중에 운영서버에서 SSL 통신 여부를 확인할 필요가 있었습니다.
보통 Linux 서버에서는 curl을 통해서 체크를 할 수 있습니다.
$ curl -v https://www.naver.com
이렇게 "-v 옵션"을 통해서 SSL 통신에 사용하는 인증서를 확인할 수 도 있고요. 하지만, curl의 경우 OS 레벨의 SSL 통신은 체크 가능하지만, JAVA Application 레벨에 SSL 통신 체크할 수 없습니다. JAVA의 경우 별도 SSL 모듈을 사용하기 때문이죠.
Java에서는 기본적으로 유효한 CA 인증기관의 인증서들을 cacerts라는 별도 키 저장소에 저장해 관리하고 있습니다. 일반적으로 대부분 CA(중계기관) 인증서를 포함하고 있습니다.
하지만, 제 업무환경은 내부망에 SSL 통신을 모니터링하는 솔루션을 사용하고 있습니다. SSL 통신 시 인증서를 가로채서 솔루션의 인증서로 바꿔서 통신하는 방식으로 동작하는 솔루션인데요. 해당 솔루션의 인증서는 사설 인증서이므로 당연히 유효한 중계기관 인증서가 아니라, SSL 통신 시 아래와 같은 오류가 발생하게 됩니다.
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed
먼저 curl 명령어에 "-v 옵션"을 통해서, 해당 시스템으로 통신하는데 사용하는 인증서를 체크해 봅니다.
$ curl -kv https://www.naver.com
당연히, 내부 솔루션에 변조된 SSL 인증서로 통신이 이루어지고 있겠죠? 그렇다면 curl 자체도 실패하게 될 겁니다. 그럴 때는 "-k 옵션"을 추가해 주시면 인증서를 무시하고 통신할 수 있습니다.
※ 사설 인증서를 Keytool 을 통해 등록해서 SSL 통신을 성공하는 부분은 다른 포스팅을 참고하시면 됩니다.
2021/01/18 - [분류 전체보기] - Java, SSL 사설 인증서 등록하기!
자, 이제 Java 소스를 통해 특정 주소의 SSL 통신이 정상적으로 동작하는지 간단하게 체크하는 코드입니다.
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.*;
public class SSLChecker {
public static void main(String[] args) {
if (args.length != 2) {
System.out.println("Usage: "+SSLChecker.class.getName()+" <host> <port>");
System.exit(1);
}
try {
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(args[0], Integer.parseInt(args[1]));
SSLParameters sslparams = new SSLParameters();
sslparams.setEndpointIdentificationAlgorithm("HTTPS");
sslsocket.setSSLParameters(sslparams);
InputStream in = sslsocket.getInputStream();
OutputStream out = sslsocket.getOutputStream();
out.write(1);
while (in.available() > 0) {
System.out.print(in.read());
}
System.out.println("Successfully connected");
} catch (Exception exception) {
exception.printStackTrace();
System.exit(1);
}
}
}
서버에 적당한 위치에 Java 소스를 올려두시거나, Local에서 Compile 후 Class 파일을 올리셔도 됩니다. (JDK가 없으면 Compile이 안 되겠죠)
# JDK 설치 경로에서 Javac로 소스를 컴파일
$ /usr/java/jdk1.8.0/bin/javac SSLChecker.java
# 컴파일된 SSLChecker 실행해 SSL 통신체크
$ java SSLChecker www.test.com 443
# 통신 성공시 성공메시지 출력!
Successfully connected
# 통신 실패시 오류메시지 출력!
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
...
...
...
통신 실패시에는 오류 메시지 내용을 토대로 디버깅하시면 됩니다.
이상입니다.
GitHub - 4ndrej / SSLPoke.java 참조
댓글