당장 구글 크롬 브라우저의 점유율이 50%가 넘어가고 있는 것 뿐만 아니라 곧 이어 다른 메이저 브라우저도 이 정책을 따라 적용할 것으로 예상되어 이의 파장은 적지 않을 것으로 보인다. 그 동안 굳이 로그인이나 민감 데이터를 서비스하지 않기 때문에 HTTP로 서비스해도 문제 없다고 생각한 사이트 운영자가 있다면 이제 심각하게 HTTPS로의 서비스 전환을 고민해야 할 때다. 그런데 HTTPS 전환을 위해서는 고려해야 할 것들이 매우 많고 복잡한데, 특히 SSL/TLS 인증서 준비부터 프로토콜 및 cipher의 구성에 특히 신경을 써야 한다. 이번 글에서는 어떻게 최적화된 HTTPS 구성을 할 수 있는지에 대해 살펴보도록 하겠다.
◇무료로 아파치 웹서버에 SSL/TLS 공인인증서 구성하기
HTTPS 서비스를 시작하려면 공인인증서를 구성하는 것부터 시작해야 하는데, 웹서버에HTTPS를 구축하려면 상용 인증서 서비스를 이용하는 것이 첫번째 해결 방안이다. 더불어 최근에는 대부분의 최신 브라우저 호환성을 안정적으로 제공하면서도 무료로 서비스를 제공하는 https://letsencrypt.org/의 이용도 증가하고 있다고 말 할 수 있다.
여기에서는 아파치(Apache) 웹서버를 운영한다고 가정하고, letsencrypt를 이용해 공인인증서를 설정하는 방법에 대해 간단히 살펴보도록 하자. 제일 먼저 해야 할 단계는 git으로 관련 파일을 설치한 후, 설치된 스크립트를 이용해 아래와 같이 실행하기만 하면 된다.
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt/
/etc/init.d/httpd stop
./letsencrypt-auto certonly --standalone
vi /etc/httpd/conf.d/ssl.conf
/etc/init.d/httpd start
아래는 vi로 ssl.conf를 설정하는 예제를 보여주고 있는데, 방금 script를 실행해 생성한 도메인의 인증서 관련 파일 위치를 SSLCertificate* 지시자에서 지정해 주면 된다.
<VirtualHost www.example.com:443>
ErrorLog logs/ssl_error_log
TransferLog logs/ssl_access_log
LogLevel warn
SSLEngine on
SSLProtocol TLSv1.2 -SSLv2 -SSLv3 -SSLv2 -TLSv1 -TLSv1.1
SSLHonorCipherOrder on
SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4"
SSLCertificateFile /etc/letsencrypt/live/www.example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/www.example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/www.example.com/chain.pem
Header always set Strict-Transport-Security "max-age=15552000; includeSubdomains;" # HSTS
</VirtualHost>
인증서에는 유효기간이 있기 때문에 만료기간 전에 연장을 해 주어야 하는데, 아쉽게도 letsencrypt 인증서는 기본적으로 90일간만 유효하다. 따라서 최소 3개월이 되기 전에 인증서를 연장해 주어야 하는데, 아래와 같은 script를 /etc/cron.monthly 등에 설치해 두면 매달 체크해 자동 연장을 하기 때문에 편리하게 이용할 수 있을 것이다.
#!/bin/sh
/etc/init.d/httpd stop >/dev/null 2>&1
/root/letsencrypt/letsencrypt-auto renew >/dev/null 2>&1
/etc/init.d/httpd start >/dev/null 2>&1
위와 같이 구성한 후 https://www.ssllabs.com/ssltest/에서 HTTPS의 서비스의 보안수준을 확인해 보면 최고 점수인 A+를 획득할 수 있게 된다.
참고로, A+를 받으려면 웹 서버에 HSTS를 활성화해야 한다. HSTS는 ‘HTTP Strict Transport Security’의 약자로서 아래와 같이 설정을 추가함으로써 간단히 구현할 수 있는데, 이와 같이 구성을 하면 한번 접속을 했던 클라이언트는 해당 기간 동안(아래의 경우 180일) 도메인에 접속시 http로 접속해도 브라우저에서 무조건 https로 자동 전환해 접속을 하게 된다.
이 정보는 브라우저의 캐시처럼 기억되어 유저가 별도로 설정을 찾아 삭제하지 않는 한 해당 기간 동안 유지되게 되므로 혹, http only로 운영중인 링크는 없는지 사전에 확인하여야 한다. 따라서 처음에는 max-age를 짧게 설정하였다가 특별히 문제가 없음을 확인한 후에 180일정도로 단계적으로 늘리는 것이 권장된다.
Header always set Strict-Transport-Security "max-age=15552000; includeSubdomains;"
◇protocol 및 cipher의 구체적인 구성 방안
이제 앞에서 언급한 구체적인 설정에 대해 하나 하나 살펴보도록 하자.
먼저 SSL/TLS Protocol은 SSLv2부터 SSLv3, TLSv1.0, TLSv1.1, TLSv1.2 등이 있으며 최근에는 TLSv1.3이 일부 시범적으로 사용되고 있다. 이 중에서 SSLv2및 SSLv3는 각각 Drown이나 Poodle취약점과 같이 암호화(encryption)를 했음에도 평문(plain text)으로 복호화(decryption)할 수 있는 심각한 보안 취약성이 발견되어 절대 사용해서는 안 되는 Protocol이다. 가장 대중적으로 사용되는 Protocol은 TLSv1.0 부터 v1.1, v1.2인데, PCI-DSS Compliance에서는 TLSv1.0도 중간자공격(man in the middle attack) 및 잠재 취약성이 있으므로 2018년 6월 이후부터는 더 이상 사용하지 말 것을 권고하고 있다.
그러나 TLSv1.0을 비활성화할 경우 윈도우 비스타나 윈도우 7의 MSIE 8-10 버전을 사용하는 유저는 https접속이 되지 않는 문제가 있으므로, 각자 접속 유저들의 환경 및 보안을 고려하여 프로토콜을 구성하는 것이 좋은데, 참고로 페이스북이나 구글, 트위터 등의 주요 사이트는 아직 오래된 환경의 유저도 고려해 TLSv1.0/1.1/1.2를 모두 지원하고는 있다.
참고로 앞에서 언급한 아파치 설정에서 아래의 의미는 최신의 암호화 알고리즘을 제공하는 TLSv1.2만 활성화하여 제공하며 나머지 하위 Protocol은 - 로 지정해 지원하지 않는다는 것을 의미하는데 각자의 환경에 따라 적절히 적용하면 된다.
SSLProtocol TLSv1.2 -SSLv2 -SSLv3 -SSLv2 -TLSv1 -TLSv1.1
그리고 특정 사이트가 어떤 프로토콜과 cipher를 지원하는지에 대해서는 https://www.ssllabs.com/ssltest/에서 조회해 보거나 nmap을 이용할 경우에는 NSE(Nmap Scripting Engine)을 이용하여 아래와 같이 실행하면 된다.
$ nmap --script ssl-enum-ciphers -p443 www.facebook.com
다음으로 살펴볼 것은 Cipher Suite라고 하는 것으로, 이를테면 다음과 같은 것이다.
◇TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
위에서 중간에 있는 WITH를 기준으로, 앞 부분은 클라이언트와 서버간 키(Key) 교환 및 인증을 담당하며 실제로 데이터를 암호화하는 부분은 WITH 뒷 부분의 설정을 통해 이루어지게 된다.
HTTPS통신에서 클라이언트와 서버는 위의 6가지 조건에 따른 협상(Negotiation)을 통해 통신을 하게 되는데, 당연히 보다 안전한 통신을 위해서는 취약한 Cipher suite를 제거하거나 필요하다면 우선순위를 낮추고, 강력한 암호화 Cipher를 이용하는 것이 좋다. 그러나 다른 한편으로는 강력하다고 무조건 좋은 것은 아닌데, 성능과 브라우저 호환성 등도 함께 고려해야 하기 때문이다.
여러가지 조합이 있을 수 있는데, 참고로, 클라이언트 유저의 브라우저 호환성을 지원하면서 안전하게 서비스 가능한 권장 cipher suite 구성중 하나는 다음과 같다.
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028)
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027)
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
TLS_RSA_WITH_AES_256_GCM_SHA384 (0x9d)
TLS_RSA_WITH_AES_128_GCM_SHA256 (0x9c)
TLS_RSA_WITH_AES_256_CBC_SHA256 (0x3d)
TLS_RSA_WITH_AES_128_CBC_SHA256 (0x3c)
TLS_RSA_WITH_AES_128_CBC_SHA (0x2f)
TLS_RSA_WITH_AES_256_CBC_SHA (0x35)
서버에서 cipher suite를 구성할 때에는 특히 순서(order)가 중요한데, 이는 클라이언트와 서버간 SSL/TLS 협상과정에서 먼저 매칭되는 cipher로 통신하기 때문에 가능하면 보다 안전하고 강력한 cipher를 먼저 정의하는 것이 좋기 때문이다. 따라서, cipher 순서를 정의할 때는 아래의 사항을 참고하기 바란다.
(1)CBC cipher는 가능한 아래쪽에 위치하도록 한다.
원활한 HTTP/2 지원을 위해 HTTP/2 Blacklist로 지정된 다음의 CBC(Cipher block chaining) 모드는 가급적 아래쪽에 설정하는 것이 좋다. :: https://tools.ietf.org/html/rfc7540#page-83 참고
-TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
-TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
-TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
-TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
(2)PFS(또는 FS)를 지원하는 cipher를 먼저 정의한다.
PFS(perfect forward secrecy)를 지원할 경우 만약 추후에 Private key가 유출되어도 이를 통해 암호화된 패킷에서 복호화를 할 수 없도록 지원하는 강력한 특성이 있다. 따라서, PFS를 지원하는 ECDHE cipher를 먼저 정의하고, PFS를 지원하지 않는 다음의 TSL_RSA cipher는 아래로 내려 우선순위를 조정하는 것이 좋다.
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_RSA_WITH_AES_128_GCM_SHA256
(3)3DES는 가급적 우선순위를 낮추거나 비활성화한다.
암호화를 할 때에는 최소한 128bit이상의 cipher를 이용하는 것이 권장사항인데, 3DES는 112bit를 이용해 취약한 것으로 알려져 있다. 이로 인해 HTTPS로 암호화를 했다 하더라도 특정한 조건에서 암호화를 임의로 해제하여 평문(plain text)으로 해독할 수 있는 sweet32라는 이름의 취약성(https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-2183)이 발견되었는데, 이는 물론 여러가지 조건이 맞아야 하는 복잡하고 지루한 공격이지만, 공격 성공 가능성이 있는 것으로 확인된 만큼 보다 안전한 서비스를 위해 미리 대처하는 것이 권장된다.
단, 3DES를 비활성화하였을 경우 Windows XP의 MSIE8을 이용하여 https를 접속할 경우 정상 접속이 되지 않게 되므로 만약 여전히 Windows XP환경을 지원해야 한다면 순서만 내리고 비활성화를 하지 않는 것이 좋다.
(4)기타 안전하지 않은 다음의 cipher는 비활성화하도록 한다.
ADH(Anonymous Diffie-Hellman) , NULL, RC4 등
마지막으로 https로 사이트를 구성할 때에는 모든 콘텐츠에 대해 Full HTTPS로 적용하는 것이 좋다. 많이 하는 실수중에 하나는 대부분의 콘텐츠는 https로 서비스하면서 실수로 특정 css파일이나 이미지 파일은 http로 절대 경로로 링크를 걸어 서비스하는 경우가 있는데 이러할 경우에는 이러한 단 하나의 이미지 파일로 인해 경고창이 뜨거나 중간자공격(man-in-the-middle attack) 에 노출되어 전체 세션을 하이재킹(hijacking)될 수도 있기 때문이다.
HTTPS 적용시에는 이외에도 performance저하나 공인인증서 만료일 관리 등 여러가지 복잡한 문제들이 있다. 그러나, 이제 HTTPS는 거스를 수 없는 trend로 접어들고 있는 것이 사실이다. 이미 HTTP보다는 HTTPS의 트래픽이 더 많은 비중을 차지하고 있고, 일부 검색엔진에서는 HTTPS가 아닌 사이트에 대해 아예 검색 결과의 우선순위를 낮추는 등 SEO에도 영향을 주고 있다. 따라서 이번 기회에 HTTPS 적용에 대해 다시 한번 고민해 보기 바라며, 지금까지 살펴본 최적의 SSL/TLS 설정 가이드에 대한 더 많은 정보에 대해서는 아래의 문서를 참고하기 바란다.
https://github.com/ssllabs/research/wiki/SSL-and-TLS-Deployment-Best-Practices
[글. 홍석범 씨디네트웍스 보안실 이사 / antihong@gmail.com]