[Network] 사설 SSL로 로컬에서 HTTPS 프로토콜 사용하기 (feat.OpenSSL, 톰캣)
HTTP로 운용하던 서버에 외부에서 데이터를 받을 일이 생겨 로컬서버, 실서버에서 SSL을 적용해 보면서 정리한 글이다.
로컬환경: Windows10, tomcat6.0.53, jdk1.7.0_80
서버환경: CentOS5.5, tomcat6.0.53, jdk1.7.0_80
HTTP프로토콜 통신은 클라이언트와 서버 사이에 주고받는 데이터를 암호화하는 기능이 없어 안전하지 않다.
보안을 강화하기 위해서는 인증기관(Certificate Authority)을 통해 SSL 인증서를 발행받은 후 HTTP에 SSL(Secure Sockets Layer) 을 추가한 HTTPS프로토콜을 사용해야 한다.
서버가 SSL 인증서를 발급받고 클라이언트와 통신하는 과정은 대략적으로 아래와 같다.
1. 서버는 내 사이트가 믿을만하다는걸 증명하기 위해 SSL을 적용하고 싶다.
2. 그래서 서버는 한쌍의 비대칭키(공개키, 개인키)를 생성해, 공개키와 서버의 정보를 인증기관(CA)에 넘기는데, 이 인증기관은 SSL인증서를 발급해주는 기관이다.
3. 인증기관은 해당 사이트가 믿을만한지 판별한 후, 자신(인증기관)의 개인키로 서버의 공개키와 정보를 암호화한 SSL 인증서를 서버에게 발급해준다.
4. 서버는 SSL 인증서를 발급받아 웹사이트를 방문하는 클라이언트의 요청을 기다린다.
5. 클라이언트는 서버가 신뢰할 수 있는 사이트인지 궁금하기 때문에 해당 사이트의 SSL 인증서를 확인한다. 근데 이 인증서가 진짜 인증기관의 인증을 받은 진짜인지, 아니면 가짜인지 알고싶다.
6. 그래서 클라이언트는 브라우저에 내장된 인증기관의 공개키로 SSL인증서에 붙어있는 서버의 정보와 공개키를 복호화한다.
7. 인증기관의 공개키로 복호화에 성공했다는 말은, 인증기관의 개인키로 인증서를 암호화했었다는 말이기 때문에 이제 클라이언트는 서버를 믿을 수 있게 된다.
8. 잽싸게 통신을 하기위해 클라이언트는 한쌍의 대칭키를 생성해, 방금 얻은 서버의 공개키로 대칭키 중 한개를 암호화해서 서버에게 전송한다.
9. 서버는 자신(서버)의 공개키로 암호화된 대칭키를 자신(서버)의 개인키로 복호화해서 클라이언트의 대칭키를 획득한다.
10. 이제 클라이언트와 서버 간 통신할때, 대칭키로 데이터를 암/복호화해 주고받는다.
실제 SSL을 적용하려면 공식적으로 인증기관에 인증서를 발급 요청해야 하지만, 테스트 환경이거나 사이트의 신뢰성이 조금 떨어져보여도 상관 없다면 우리 자신이 인증기관이 되어 SSL인증서를 발급해 서버에 적용할 수도 있다.
인증서를 만들때는 서버의 정보와 키 등을 포함한 키스토어 파일이 필요하다. 톰캣에서는 두가지 키스토어 타입을 지원하는데, openssl로 만든 pkcs12타입과 jdk의 keytool로 만든 jks이다.
두가지 방식 모두 크게 복잡하진 않지만 자바가 깔려있는 나로써는 jks로 생성하는게 더 간편했다.
[jdk keytool을 이용한 jks 방식]
1. 인증서를 생성할 디렉토리로 이동, 터미널 실행
2. keytool -genkey -keyalg RSA -keystore keystore.jks 명령을 통해 RSA 알고리즘의 keystore.jks 파일을 생성한다.
3. 입력 프롬프트가 나타나면 키 저장소 비밀번호를 입력한다 (아래 keystorePass속성값에 사용되므로 기억해둬야함)
4. 이름과 성(Common Name)을 입력한다. 로컬에서는 localhost, 서버에서는 서버 도메인명을 입력해 준다.
5. 나머지 옵션은 엔터로 스킵해도 되고, 아무거나 입력해주자
6. <mykey>에 대한 키 비밀번호를 입력할 땐 엔터를 눌러서 위에 입력한 비밀번호를 그대로 사용한다.
7. 실행할 톰캣 설치경로 /conf/server.xml 파일을 열어 아래 코드를 추가한다. keystoreType속성은 기본값이 JKS이기 때문에 생략해도 된다. 로컬에서는port 값을 8443, 서버에서는 443를 입력해줬다.
<Connector protocol="HTTP/1.1"
port="8443" SSLEnabled="true" maxThreads="200"
scheme="https" secure="true"
keystoreType="JKS"
keystoreFile="생성한 JKS 키스토어 파일경로"
keystorePass="생설할때 입력한 키스토어 패스워드" clientAuth="false"
sslProtocol="TLS" />
8. 톰캣을 실행하고 https://localhost:8443 에 접근한다.
[openssl을 이용한 pcks12 방식]
1. 인증서를 생성할 디렉토리로 이동, 터미널 실행, openssl 입력
2. genrsa -aes256 -out ca_private.key 2048 명령어로 AES256방식으로 2048bit의 루트 인증기관이 사용할 ca_private.key 개인키 파일 생성
3. 입력 프롬프트가 나타나면 개인키 비밀번호 입력
4. req -new -key ca_private.key -out ca_csr.csr 명령어로 2번에서 만든 개인키와 인증기관의 정보를 담은 ca_csr.csr인증요청서를 생성
5. 입력 프롬프트가 나타나면 개인키 비밀번호 입력
6. 기타 자잘한건 다 엔터로 패스하거나 아무거나 입력 후 Common Name은 인증기관의 도메인명 (아무거나 입력)
7. x509 -req -days 3650 -extensions v3_ca -set_serial 1 -in ca_csr.csr -signkey ca_private.key -out ca_crt.crt 명령어로 ca_csr.csr을 ca_private.key로 서명한 pki x509 버전3의 3650일짜리 ca_crt.crt 인증서 파일을 생성한다.
8. 입력 프롬프트가 나타나면 개인키 비밀번호 입력
9. 인증서가 제대로 생성됐는지 x509 -text -in ca_crt.crt 명령어로 확인
10. 이제 자신의 서버 인증서를 생성해야 하는데 위에서 한 내용과 거의 동일하니 자세한 설명은 생략하겠다.
11. genrsa -aes256 -out localhost_private.key 2048
12. req -new -key ca_private.key -out ca_csr.csr 입력 후 Common Name을 입력해 줄 때 인증기관의 도메인명과 동일한 도메인명을 입력하면 안된다고하니 주의하자
13. x509 -req -days 3650 -extensions v3_user -in localhost_csr.csr -CA ca_crt.crt -CAcreateserial -CAkey ca_private.key -out localhost_crt.crt 명령어로 localhost_crt.crt 서버 인증서 파일을 생성
14. 톰캣이 지원하는 pkcs12타입의 인증서로 변환시키기 위해 pkcs12 -export -in localhost_crt.crt -inkey localhost_private.key -out localhost.keystore 명령어로 localhost.keystore 키스토어 파일 생성
15. 입력 프롬프트가 나타나면 localhost_private.key의 비밀번호를 입력해주고, export password에 키스토어 패스워드를 입력해준다 (아래 keystorePass속성값에 사용되므로 기억해둬야함)
16. 실행할 톰캣 설치경로 /conf/server.xml 파일을 열어 아래 코드를 추가한다. keystoreType속성은 기본값이 JKS이기 때문에 PKCS12로 설정해야 한다. 로컬에서는port 값을 8443, 서버에서는 443를 입력해줬다.
<Connector protocol="HTTP/1.1"
port="8443" SSLEnabled="true" maxThreads="200"
scheme="https" secure="true"
keystoreType="PKCS12"
keystoreFile="생성한 키스토어 파일경로"
keystorePass="EXPORT PASSWORD에 입력했던 키스토어 패스워드" clientAuth="false"
sslProtocol="TLS" />
17. 톰캣을 실행하고 https://localhost:8443 에 접근한다.
*참고사항
1. 터미널을 열때 관리자 권한으로 실행하는게 확실하다.
2. keytool로 jks 키스토어 파일을 만들때, 만든 환경의 jdk버전과 적용할 서버의 jdk버전이 같아야 한다.
3. jdk1.6버전 이하라면 톰캣 실행 시 TLSv1 프로토콜이 실행되기 때문에 크롬 기반의 브라우저에서는 보안상의 이유로 접근을 차단한다. 때문에 jdk1.7이상을 다운받아 환경변수로 등록해주던가, 톰캣 설치경로/bin/catalina.sh 파일을 열어
JAVA_HOME=jdk1.7이상설치경로
를추가해준다. 현재 실행중인 로컬호스트의 인증서 정보와 프로토콜 정보를 알고싶다면 openssl s_client -connect localhost:포트번호 명령어로 확인해볼 수 있다.
4. 톰캣설치경로/conf/server.xml 파일에 들어가는 xml코드는 대소문자를 구분한다고 하니 웬만하면 복붙을 하자.
5. Common name 입력 시, 원래 FQDN (DNS로 등록된 도메인명)을 입력해 줘야 하지만, ip주소로 입력해도 적용은 됐다.
6. 요즘은 SSL보다 보안이 상향된 TLS프로토콜을 사용하지만 실상 SSL라고 부른다고 한다.
같이 보면 좋은 글 [http프로토콜과 3-way handshaking, 대칭키/비대칭키 암호화]