자바 SSL 을 이용하여 간단하게 통신하는 방법을 다루겠습니다.
SSL 이란 전송 계층 보안(영어: Transport Layer Security, TLS, 과거 명칭: 보안 소켓 레이어/Secure Sockets Layer, SSL)는 컴퓨터 네트워크에 통신 보안을 제공하기 위해 설계된 암호 규약입니다. 서버 사이에 전송된 데이터를 암호화하여 제3자가 도청이나 데이터를 훔치는 일을 방지하는 역할을 합니다. 그리고 암호화를 해서 최종단의 인증, 통신 기밀성을 유지시켜줍니다.
그러면 자바에서 SSL을 이용하는 방법에 대해 알아보도록 하겠습니다. 본 예제를 구성하고 테스트하기 전 기본적인 상식과 환경설정이 요구됩니다. 처음부터 천천히 따라와주시는 것을 권장합니다.
SSL에서는 데이터를 암호화해서 전송하므로 본 문서의 암호화 과정은 RSA 공개키 암호를 사용하였습니다.
# Contents
- TrustStore KeyStore 설명 및 차이점
- 개발환경 및 설정
- 예제
# TrustStore KeyStore 설명 및 차이점
1. 구성도
먼저 SSL 구성도부터 알아보겠습니다. SSL 구성도는 아래 그림을 참고해주세요.
위는 서버와 클라이언트에서 각각 무슨일을 하는 지 알려주는 그림입니다. 간단 명확하게 표시되어 있어서 이해하기 쉬운 그림이라고 생각합니다.
먼저, 서버와 클라이언트는 Java 베이스의 JRE 가 설치되어 있습니다. 이 JRE 환경. 즉, 자바실행환경에서 서버는 KeyStore에서의 정보를 클라이언트에게 전송합니다. 이 정보를 우리는 공개키라고합니다. 이 공개키를 클라이언트 측에 전송을 하고, 클라이언트 측은 TrustStore에 저장하게 됩니다.
클라이언트는 서버에게 Request를 요청할 때, 다시 KeyStore에 있는 키를 이용하여 Server에 접근하고, Server는 TrustStore를 통해 인증이 성공하면 3-way-handsake를 하게 됩니다.
아래 내용은 https://www.geeksforgeeks.org/difference-between-truststore-and-keystore-in-java/ 사이트를 해석한 내용입니다.
TrustStore 는 SSL 연결 에서 서버가 제공한 인증서를 확인하는 인증 기관(CA)의 인증서를 저장하는 데 사용됩니다 . 하지만 KeyStore는 특정 프로그램 검증을위한 양 당사자 (서버 또는 클라이언트)에 제출해야 개인 키 및 ID 인증서를 저장하는 데 사용됩니다. 이것은 그들이 서로 반대라는 결론을 내립니다. 인증에서 trustStore는 다른 사람을 식별하는 식별 인증서를 보유하고 keyStore는 우리를 보유하는 식별 인증서를 보유한다고 직접 결론을 내릴 수 있습니다.
여기 프로그래밍 언어에서와 같이 Java에서 이 개념은 타사 응용 프로그램과 통신하려고 할 때마다 사용됩니다.
TrustStore와 KeyStore의 차이점은 아래 표 내용에 나와 있습니다.
TrustStore에는 개인 정보와 민감한 정보가 포함되어 있지 않습니다. |
keyStore에는 개인 정보와 민감한 정보가 포함되어 있습니다. |
javax.net.ssl.trustStore는 TrustStore를 지정하는 데 사용됩니다. |
javax.net.ssl.keyStore는 키 저장소를 지정하는 데 사용됩니다. |
클라이언트 측에서 성공적인 연결을 위해서는 TrustStore 설정이 필요합니다. |
SSL에서 서버 측을 설정할 때 keyStore가 필요합니다. |
TrustStore는 다른 사람의 자격 증명을 저장합니다. | keyStore는 자격 증명을 저장합니다. |
TrustStore는 신뢰하는 외부 시스템의 인증서를 보유합니다. | KeyStore는 애플리케이션의 인증서를 보유합니다. |
TrustStore 비밀번호는 다음 확장자 Djavax.net.ssl.trustStorePassword로 제공됩니다. |
KeyStore 비밀번호는 Djavax.net.ssl.keyStorePassword 확장자로 지정됩니다. |
TrustStore 및 TrustStore 암호는 일반 파일에 저장되며 모두가 볼 수 있습니다. | 키 저장소 및 키 암호는 해당 그룹의 구성원만 읽을 수 있는 파일에 일반 텍스트로 저장됩니다. |
본 문서를 제공해주신 @pranaythanneru 님에게 감사드립니다.
# 개발환경 및 설정
1. 서버
- 자바 JDK
- 환경변수 설정
2. 클라이언트
- 자바 JRE 이상
3. 환경 변수 확인
먼저 설치된 자바의 환경변수가 설정되어 있는지 확인해 볼 필요가 있습니다.
CMD 창을 열어서 아래 명령어를 통해 환경변수 설정이 되어있는 지 확인해주세요.
java -version
javac -version
자바 버전이 이렇게 출력되어도, 아래와 같은 명령어를 입력하여 자바가 설치된 경로를 파악해주세요. 여기서 많이 나오는 실수는 openJDK 버전을 설치한 개발자분들은 환경변수 설정이 jdk\bin으로 되지 않아 에러가 뜨는경우가 있습니다. 그렇기 때문에 아래 명령어를 확인하여주시기 바랍니다. 본 명령어는 환경 변수로 설정한 모든 스트링을 읽는 명령어입니다. 이 명령어도 CMD 에 입력합니다.
echo %path%
그리고 Java가 설치된 경로로 이동해주세요. 이동한 경로에는 아래와 같은 keytool.exe 프로그램이 존재하여야 합니다.
환경 변수 확인 뿐 아니라 자바에서 SSL 키를 생성하기 위한 Tool이 있는지도 확인해보았습니다. 자바를 설치했으나 환경변수가 되지 않으신 분들은 환경변수를 설정해주세요. 환경변수는 본 게시물에서는 설명하지 않겠습니다.
이 다음에는 본격적인 Java 네이티브 환경에서 기초적인 SSL 인증방법입니다.
# 예제
서버에서 작업을 해야합니다. 서버와 클라이언트는 한개의 PC로 작업할 수 있습니다. 저는 편의 상 1개의 PC로 작업을 하도록 하겠습니다.
0. 테스트 기본 폴더 생성 및 cmd 열기
이 부분은 선택사항입니다. 테스트를 쉽게 하기 위해 바탕화면에 test라는 폴더와 함께 cmd 창을 띄우겠습니다.
1. 키 생성
먼저 keytool 을 통해 KeyStore를 생성해주세요. 아래는 keytool 포맷 형식과 예시입니다. 아래 명령어를 입력 한 후 비밀번호 6글자 이상을 눌러주세요.
keytool -genkey -v -keystore <keyName> -alias <alias> -keyalg RSA -keysize 2048 -validity 10000
# example
# keytool -genkey -v -keystore server -alias server -keyalg RSA -keysize 2048 -validity 10000
2. 인증서 추출
생성된 KeyStore를 통해 인증서를 추출합니다. 추출된 인증서는 클라이언트 쪽으로 보냅니다.
keytool -export -alias <alias> -keystore server -rfc -file <cerFileName>.cer
# example
# keytool -export -alias server -keystore server -rfc -file trustServer.cer
3. 인증서 등록
인증서를 등록하기 위해 클라이언트에서 작업합니다. 아래 명령어를 통해 공개키를 클라이언트에 등록합시다. 여기서 주의할 점은 cacerts path 입니다. cacerts 를 넣을 때, JRE path에다가 넣으시려면 \JDk_PATH\jre\lib\security\cacerts 를 직접 입력하셔야 합니다.
keytool -importcert -alias <alias> -file <cerFileName>.cer -keystore <cacerts path> –storepass changeit
# example
# keytool -importcert -alias trustServe -file trustServer.cer -keystore "C:\Program Files\Java\jdk1.8.0_301\jre\lib\security\cacerts" –storepass changeit
# keytool -importcert -alias trustServe -file trustServer.cer -keystore cacerts –storepass changeit
4. 서버 코드
해당 코드는 아주 간단한 예제입니다. 경로만 변경해주시고 테스트해주세요.
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class EchoServer {
public static void main(String[] arstring) {
System.setProperty("javax.net.ssl.keyStore","C:\\Users\\JHKIM\\Documents\\Java\\SSL_Tutorial\\src\\server");
System.setProperty("javax.net.ssl.keyStorePassword","123456");
System.setProperty("javax.net.debug","ssl");
try {
SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslserversocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(9999);
SSLSocket sslsocket = (SSLSocket) sslserversocket.accept();
InputStream inputstream = sslsocket.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
String string = null;
while ((string = bufferedreader.readLine()) != null) {
System.out.println(string);
System.out.flush();
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
5. 클라이언트 코드
해당 코드는 아주 간단한 예제입니다. 경로만 변경해주시고 테스트해주세요.
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.*;
public class EchoClient {
public static void main(String[] arstring) {
System.setProperty("javax.net.ssl.trustStore", "C:\\\\Users\\\\JHKIM\\\\Documents\\\\Java\\\\SSL_Tutorial\\\\src\\\\cacerts");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
System.setProperty("javax.net.debug","ssl");
try {
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("localhost", 9999);
InputStream inputstream = System.in;
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
OutputStream outputstream = sslsocket.getOutputStream();
OutputStreamWriter outputstreamwriter = new OutputStreamWriter(outputstream);
BufferedWriter bufferedwriter = new BufferedWriter(outputstreamwriter);
String string = null;
while ((string = bufferedreader.readLine()) != null) {
bufferedwriter.write(string + '\n');
bufferedwriter.flush();
}
}
catch (Exception exception) {
exception.printStackTrace();
}
}
}
'기초 문법 > 자바' 카테고리의 다른 글
[JAVA] AES128 암호화/복호화 (0) | 2021.09.24 |
---|