SSL/TLS 란?

TLS(Transport Layer Security) 는 인터넷 상에서 통신할때 주고 받는 데이타를 보호하기 위한 표준화된 암호화 프로토콜의 이름이다. TLS는 넷스케이프사에 의해 개발된 SSL(Secure Socket Layer) 버전 3.0을 기반으로 하고 있으며 현재는 2008년 발표된 TLS 버전 1.2 가 최종 버전이다.

TLS 는 전송계층(Transport Layer)의 암호화 방식이기 때문에 HTTP 뿐만 아니라 FTPXMPP 등 응용계층(Application Layer) 프로토콜의 종류에 상관없이 사용할 수 있는 장점이 있다. 기본적으로 인증(Authentication), 암호화(Encryption), 무결성(Integrity)을 지원한다.

SSL 에서 TLS로 이름이 변경된지 오래됐지만 아직도 사람들은 TLS 대신 SSL 이라는 단어를 더 많이 사용하고 있다. 실제로 SSL/TLS 의 오픈 소스 구현물인 프로젝트의 이름은 아직도 OpenSSL 이기도 하다.

또한 TLS 의 가장 중요한 적용이 HTTPS 이다 보니 SSL 을 HTTPS 와 혼용하여 사용하는 경우도 많다. 이 책에서는 SSL 이라고 할 경우 SSL/TLS 프로토콜을 의미하며 보안이 적용된 HTTP 는 HTTPS 로 지칭할 것이다.

TLS 아키텍처

 

암호/해쉬/전자서명

mod_ssl 의 동작과 설정에 대해 이해하려면 약간의 암호학적 지식과 공개키 기반 구조(PKI - Public Key Infrastructure) 에 대한 지식이 필요하다. 

이 방면에 사전 지식이 없는 독자들을 위해 SSL 이해에 필요한 정도의 내용을 설명하고자 한다.

암호화와 복호화의 의미에 대해서는 다들 알고 있을 테니 간단하게 암호화 방식에 대해서 알아 보자.


대칭키 방식 암호화

암호문을 생성(암호화)할 때 사용하는 키와 암호문으로부터 평문을 복원(복호화)할 때 사용하는 키가 동일한 암호 시스템이다.

하나의 키로 암호화와 복호화를 수행하므로 대칭키(Symmetric key) 또는 비밀키(Secret Key) 방식의 암호화라고 한다.


주요 알고리즘으로는 예전에 유닉스의 패스워드 파일을 암호화하는데 사용했던 DES와 현재 미국의 표준 암호 알고리즘인 AES가 있으며 국내에서 개발한 SEED와 ARIA , 그리고 유럽에서 개발한 IDEA 알고리즘 등이 있다.


대칭키 방식은 하나의 키만 사용하므로 상대방과 대칭키 기반으로 암호화 통신을 할 경우 상대방도 사전에 같은 키를 갖고 있어야 한다.

대칭키의 단점은 키를 상대방과 안전하게 공유하는 것은 굉장히 어렵다는 점이다. (키를 보내는 중간에 유출될 우려가 있다. 비밀 편지를 가져가는 전령이 잡히면 어떻게 될지 생각해 보자.)

그리고 여러 상대방과 통신할 경우 각각의 대칭키를 관리하기가 어렵다는 단점이 있다.

공개키 방식 암호화

공개키 방식(Public Key)의 암호는 암호학적으로 연관된 두 개의 키를 만들어서 하나는 자기가 안전하게 보관하고  다른 하나는 상대방에게 공개한다.

본인만 갖고 있는 키를 개인키(Private Key)라고 하며 상대방에게 공개하는 키는 공개키(Public Key) 라고 한다.

 

대표적인 공개키 알고리즘으로는 RSA, Elgamal 등이 있으며  전자서명에 사용하는 DSA(Digital Signature Algorithm), KCDSA 등도 공개키 알고리즘에 포함된다. (DSA, KCDSA 는 암호기능이 없고 전자 서명만 가능하다.)

 

송신자는 상대방과 암호화된 통신을 할 경우 다음 그림과 같은 절차를 거친다.

  1. 송신자는 수신자의 공개키를 구한다.
  2. 송신자는 수신자의 공개키로 평문을 암호화 한다.
  3. 송신자는 암호화된 메시지를 상대방에게 전달한다. 메시지는 암호화되어 있으므로 전달 도중에 유출되거나 도청되도 암호문으로부터 원문을 알아내기가 어렵다.
  4. 수신자는 자신의 비밀키로 암호화된 메시지를 해독하여 평문을 얻는다. 

공개키로 암호화한 메시지는 수신자의 개인키로만 해독할 수 있으므로 보안 채널을 구성할 때 대칭키에 비해서 많이 유리하다.

 
공개키 방식 암호화

이제 독자들은 공개키 방식의 장점을 이해했을 것이다. 그러면 공개키 방식의 단점은 무엇일까.

그것은 바로 대칭키 방식에 비해서 속도가 매우 매우 매우 느리다는 것이다.

매우라는 부사를 여러 번 쓴 이유는 공개키 방식은 대칭키에 비해 비교가 안 될 정도로 느리므로 전자 서명이나 간단한 메시지 암호화 등에는 사용할 수 있지만 실시간 암호화 통신등에는 속도 문제 때문에 사용할 수가 없다.

 

이로 인해 암호화 통신에서 공개키 기반은 대칭키로 사용하는 키(세션 키라고도 한다)를 상대방의 공개키로 암호화하여 안전하게 전달하는 용도로 사용하고 있으며, 실제 암호화 통신은 이렇게 안전하게 전달 받은 대칭키를 가지고 이루어 진다. SSL/TLS 역시 이와 같은 방식으로 동작한다.

Message Digest

메시지 다이제스트는 임의의 입력이 있을 경우 정해진 길이의 출력을 하는 일방향 함수(One Way function)을 의미한다. 알고리즘에서 이야기하는 해시(Hash) 함수라고 생각하면 된다.

유명한 알고리즘으로는 MD5(보안 문제때문에 많이 사용 되지 않는다), SHA1, SHA-2(SHA256, SHA384, SHA512) 등이 있다.

 

SSL /TLS 프로토콜

TLS 핸드셰이크 절차

위 그림을 보면 전체적인 SSL/TLS 프로토콜의 절차가 이해될 것이다. 절차를 간략하게 요약하면 다음과 같다.

  1. 클라이언트와 서버는 헬로 메시지로 기본적인 정보를 주고 받는다. (1, 2)
  2. 서버는 서버가 사용하는 SSL/TLS 인증서를 전달한다. (3, 4)
  3. 클라언트는 암호화 통신에 사용할 대칭키를 생성하고 사이를 서버에 전달한다(5). 이 과정을 키 교환(Key Exchange) 라고 하며 디피-헬만 키 교환(Diffie–Hellman key exchange) 또는 RSA 를 많이 사용한다. 
  4. 클라이언트는 암호화 통신에 사용 가능한 암호 알고리즘과 해시 알고리즘 목록을 서버에 전달한다. (6, 7)
  5. 서버도 알고리즘 목록을 교환후 핸드쉐이크가 종료되며 이제 클라이언트와 서버는 암호화 통신에 필요한 대칭키를 서로 보유하게 된다.(8, 9)

위 과정이 끝나면 SSL 세션이 구축되며 실제 암호화 통신을 시작할수 있다.

mod_ssl

mod_ssl은 SSL 의 오픈 소스 구현물인 OpenSSL 라이브러리를 사용하여 HTTPS 를 구현한 확장 모듈이다. 아파치 웹서버 버전 1은 외부 모듈이라 별도로 설치해야 했지만 2.x 대 부터는 기본 모듈에 포함되었다.

이제 mod_ssl 을 설치하고 HTTPS 서비스를 구축하여 웹에 강력한 암호화 방식을 적용해 보자.

 

설치

mod_ssl 은 httpd 와 openssl 패키지에 의존성이 있지만 사전에 이미 설치하였으므로 설치하지 않아도 된다.

설치되지 않았더라도 yum 으로 설치할 것이므로 mod_ssl 을 설치하면 의존성 관계에 의해 아파치 httpd 도 자동으로 설치 된다. 다음 명령어로 모듈을 설치하자.

yum install mod_ssl

아파치 모듈 파일인 mod_ssl.so 는 /etc/httpd/modules/ 에 설정 파일인 ssl.conf는 /etc/httpd/conf.d/ 에 설치가 완료된다.

 

설정

이제 conf.d/ssl.conf 설정 파일의 내용을 살펴 보자. mod_ssl 의 지시자중 전역적으로 설정하는 지시자는 변경할 일이 없으므로 가상 호스트별 설정해야 하는 지시자들을 위주로 알아 보자.

<VirtualHost *:443>

ServerName example.com
ServerAlias www.example.com
SSLEngine on
SSLProtocol all -SSLv2

SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW
SSLCertificateFile /etc/pki/tls/certs/localhost.crt
SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
ErrorLog logs/jira-ssl-error_log
TransferLog logs/jira-ssl-access_log
CustomLog logs/ssl_request_log \
"%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" 

</VirtualHost>

 

SSLEngine

SSL 엔진의 구동 여부를 설정한다. off 로 설정하면 동작하지 않는다.

 

SSLProtocol

클라이언트와 통신시 사용할 프로토콜 버전을 지정한다. 사용 가능한 버전 문자열은 SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2 이다. all 로 적으면 모든 버전을 사용하게 되며 제외할 프로토콜이 있을 경우 - 부호를 붙인다.

기본 설정인 all -SSLv2 는 모든 버전을 사용하지만 보안에 취약한 SSLv2 는 사용하지 않겠다는 의미이다.

TLS 프로토콜 1.1 이상을 사용하려면 OpenSSL 버전이 1.0.1 이상이어야 한다. 현재 CentOS 6 에 탑재된 아파치 웹서버는 TLS 1.2 까지 지원하지만 SSLProtocol  지시자에 명시적으로 TLSv1.1, TLSv1.2 는 사용할 수 없다.

이는 아파치 2.2.22 이상에서만 사용 가능한 지시자인데 탑재된 버전은 2.2.15 이기 때문이다.

다음과 같이 설정하면 SSL 대신 TLS 만 사용하게 되며 세부적인 TLS 버전은 브라우저와 협상하여 결정한다.

SSLProtocol TLSv1

 

SSLCipherSuite

사용할 암호 알고리즘을 설정한다. 특별히 선호하는 알고리즘이 있지 않은 이상 수정할 일이 많지 않다.

 

SSLCertificateFile

PEM 형식으로 저장된 인증서 파일의 경로를 설정한다. 이 인증서는 웹 서비스를 제공하는 서버가 사용하는 인증서로 보통 VeriSign, Comodo, thawte 등 해외의 인증기관에서 발급 받는다.

인증기관에서 발급받으면 비용이 발생하지만 이 인증기관들은 웹 브라우저의 신뢰하는 인증 기관 정보에 포함되어 있으므로 브라우저가 HTTPS 로 연결할 경우 아래와 같은 경고가 발생하지는 않는 장점이 있다.

브라우저 보안 경고

내부에서 사용하는 서비스라면 비용을 들일 필요없이 자체적으로 만든 인증서를 사용해도 된다.

RHEL과 CentOS 는 인증서를 /etc/pki/tls/certs 디렉터리에 저장하며 SELinux 의 보안 컨텍스트도 여기에 맞춰져 있으므로 꼭 이 경로에 설치해야 한다.

 

(info) PEM(Privacy Enhanced Mail) 이란

PEM 은 Base64 형식으로 인코딩된 인증서 형식을 의미한다. 에디터로 열어서 -----BEGIN CERTIFICATE----- 로 시작하는 부분이 있으면 PEM 형식이고 바이너리 데이타면 DER 형식이다.

mod_ssl 은 PEM 을 사용하므로 DER 형식의 인증서가 있다면 openssl 명령어를 통해서 PEM 으로 변환해야 한다.

openssl x509 -inform der -in certificate.cer -out certificate.pem

SELinux 주의

인증서와 개인키가 존재하는데 웹서버가 읽지 못할 경우 SELinux 가 원인인 경우가 있다.

차단하는 주요 원인은 잘못된 보안 컨텍스트때문이며 인증서와 개인키를 저장하는 /etc/pki/tls/ 의 컨텍스트는 cert_t 이어야 한다.
SELinux 의 restorecon 또는 chcon 명령으로 해결하자.

 

SSLCertificateKeyFile

공개키와 쌍을 이루는 개인키의 경로를 지정한다. CentOS는 /etc/pki/tls/private 디렉터리에 저장하며 개인키는 유출되면 안 되므로 루트외에는 읽을 수 없게 다음과 같이 설정하는 게 좋다. 

chmod 700 /etc/pki/tls/private/

기본적으로 개인키 파일을 생성할 때 암호(Passphrase)를 넣어야만 사용할 수 있게 되어 있다. 암호로 보호되는 개인키를 웹 서버에서 SSL 용으로 사용할 경우  웹 서버를 구동할때 마다 암호를 입력해야 한다.

이는 서비스의 자동화에 방해가 될 수 있으므로 개인키를 보호하는 암호를 없애고 사용하고 싶은 경우 openssl 명령어를 사용하여 암호를 제거한 개인키를 만들수 있다.

  1. 기존 개인키를 백업용으로 복사한다.

    cp  /etc/pki/tls/private/example.com.key  /etc/pki/tls/private/example.com.key.enc

     

  2. openssl 명령어를 사용하여 개인키의 암호를 제거한다. 이때 기존 암호를 넣어야 한다.

    openssl rsa -in  /etc/pki/tls/private/example.com.key.enc -out  /etc/pki/tls/private/example.com.key

     

SSLCACertificateFile

PEM 형식으로 된 SSL 인증서를 발급한 인증기관의 인증서 목록 파일을 설정한다. 위에서 언급한 SSL 인증서 발급 기관이라면 보통 브라우저에 인증기관 인증서가 포함되어 있으므로 설정하지 않아도 서비스에 문제가 없다.


로그 파일 설정

SSL 가상 호스트마다 ErrorLog, TransferLog 지시자로 로그 파일을 지정할 수 있다. 

HTTP 로 들어온 요청과 구분하기 위해 별도의 로그 파일로 분리하는게 좋으며 SSL 일 경우 프로토콜 버전과 사용하는 암호 정보를 기술하는 별도의 로그 파일을 CustomLog 지시자로 지정할 수 있다.

SSL 로그 파일은 다음과 같이 TLS 프로토콜 버전과 사용하는 알고리즘이 남게 된다. 로그를 보면 최신 브라우저들은 SSL 대신 TLS를 사용하는것을 알 수 있다.

TLS 로그파일

[30/Jul/2014:19:40:41 +0900] 210.181.192.103 TLSv1.2 DHE-RSA-AES128-GCM-SHA256 "GET / HTTP/1.1" 5039 "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36"
[30/Jul/2014:19:41:12 +0900] 210.181.192.103 TLSv1.2 DHE-RSA-AES128-SHA "GET / HTTP/1.1" 5039 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0"
[30/Jul/2014:19:42:03 +0900] 210.181.192.103 TLSv1 AES128-SHA "GET / HTTP/1.1" 5039 "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

 

웹서버 재구동

설정이 끝났다면 service httpd restart 명령어로 웹서버를 재구동하여 SSL/TLS 동작 여부를 확인해 보자. 사용하는 웹 브라우저의 URL 에  https 를 명시하여 연결해도 되며 리눅스 커맨드라면 유틸리티 장에서 익힌 curl 명령어를 사용해도 된다.

curl 은 SSL/TLS 연결시 서버의 인증서를 검증하므로 인증기관에서 발급 받은 인증서가 아닐 경우 -k, --insecure 옵션을 추가해야 한다. -v 옵션을 추가하면 핸드쉐이크 과정도 표시해 준다.

curl -k -v -J https://example.com/

 

SSL 가상 호스트

여러 개의 SSL 사이트가 있을 경우도 웹 서버의 가상 호스트 기능을 이용하여 하나의 장비의 서비스 가능하다. 먼저 conf.d/ssl.conf 에 이름 기반 가상호스트를 사용하겠다는 설정을 추가하자. SSL 이므로 포트명에 443을 추가해야 한다.

NameVirtualHost *:443

그리고 <VirtualHost *:443> 항목의 ServerName, ServerAlias 에 가상 호스트 이름을 넣고 사용할 SSLCertificateFile, SSLCertificateKeyFile 등  가상 호스트마다 달라져야 할 설정을 추가해 주면 된다.

단 SSL 가상 호스트는 HTTP 기반 가상호스트와 달리 주의해야 할 점이 하나 있다.

 

서버 이름 표시(SNI - Server Name Indication)

전 절에서 가상 호스트는 HTTP의 Host: 헤더를 사용하여 웹서버가 처리한다고 내용을 기억할 것이다. 브라우저가 Host: 헤더를 웹서버에 전송하려면 연결이 이루어진 후에 가능하다.

그런데 SSL 은 HTTP 보다 하위 레이어이므로 SSL 세션 구축은 HTTP 연결보다 먼저 이루어 진다. 

SSL 핸드쉐이크 단계 3에서 이미 서버의 SSL 인증서를 전송받았는데 브라우저가 요청하는 가상 호스트가 이미 받은 SSL 인증서에 있는 주소와 다를 경우 브라우저는 신뢰할 수 없는 사이트라고 판단하게 된다.

 

이는 SSL 이 HTTP 보다 하위 레이어라 발생하는 일이며 HTTP 프로토콜에서는 처리할 수 있는 방안이 없다.

SSL/TLS 표준에서는 이 문제를 해결하기 위해 SSL 핸드쉐이크내에 도메인 이름을 보내게 표준이 확장되었고 이 기능을 서버 이름 표시라고 한다.

 

그러므로 SSL 가상 호스트를 사용하려면 변경된 표준을 웹 서버, 웹 브라우저, 또는 사용하는 SSL 라이브러리가 지원해야 한다.

CentOS6 에 탑재된 아파치 웹서버는 이 기능을 지원하므로 문제가 없고 윈도 사용자는 비스타 이상의 버전을 사용해야 문제가 없다. 

Java 의 경우 JDK7 이상이어야 서버 이름 표시 기능을 지원한다.

 

마치며

이번 장에서 아파치 웹서버 설정 및 중요한 모듈의 사용법에 대해서 익혔다. 

웹서버는 정적 데이타 처리를 하고 WAS 서버는 어플리케이션을 처리하도록 역할이 나눠지고 있지만 여전히 웹 서버는 매우 중요한 역할을 수행한다.

그중에 가장 중요한 역할중 하나는 고객과 WAS 를 연결해주는 게이트웨이로서의 역할이다.

 

다음 장에서는 톰캣에 대해서 알아보고 톰캣과 아파치 웹서버를 연동하여 WAS 를 아파치 뒤에서 서비스하는 방법을 배우게 된다.

특히 리버스 프락시 방식은 연계하려는 WAS 의 종류에 상관없이 아파치로 서비스할 수 있는 기법이니 철저하게 익혀두기 바란다.

 

이 책을 쓰는 현재 RHEL 7 이 공식 출시되었고 7에는 아파치 2.4 가 탑재되어 있다.

아파치 2.4는 비동기 IO, 이벤트 기반 처리, 낮은 메모리 사용등 수많은 개선이 이루어졌고 RHEL 7 공식 출시에 따라 사용량이 많이 늘어날 것으로 예상된다.

독자들은 아파치 2.4에도 관심을 가져 주기를 바라며 또한 신흥 강자인 NGINX 도 훌륭한 웹서버이니 구축하려는 웹 서비스의 용도와 목적에 맞게 적절한 웹서버를 선택하여 고품질 서비스를 제공할 수 있기를 기원한다.





blog comments powered by Disqus