DROWN Attack 취약점 방지용 SSL 설정
https://www.ssllabs.com 에서 SSL 테스트를 해봤는데 DROWN 취약점이 있다고 F 등급을 먹인다.
DROWN 공격 취약점에 대한 내용
- https://sarc.io/index.php/httpd/581-openssl-suites
- http://blog.alyac.co.kr/554
2026년 수정 안내 이 글에 세 가지 부정확한 내용이 있었다. “SSL v1”은 공개 배포된 적이 없고, DROWN은 SSLv2 전용 취약점이라 TLS 1.0과는 무관하며,
default_server가 서버 전체에 하나만 있어야 한다는 서술도 틀렸다. 바로잡는다.
DROWN이 무엇인가
DROWN(CVE-2016-0800)은 SSLv2를 이용해 TLS 통신을 복호화하는 크로스 프로토콜 공격이다. 공격 대상 서버가 TLS만 쓰고 있어도, 같은 RSA 키를 쓰는 다른 서버 어딘가에 SSLv2가 켜져 있으면 그쪽을 오라클로 삼아 TLS 세션을 깰 수 있다는 것이 이 공격의 핵심이다.
따라서 DROWN을 막는 조건은 하나다. SSLv2를 어디에서도 쓰지 않는 것.
참고로 SSL v1은 스펙 단계에서 폐기되어 공개 배포된 적이 없다. 실제로 존재한 것은 SSLv2(1995), SSLv3(1996)뿐이다.
TLS 1.0/1.1을 끄는 것은 DROWN과 무관한 별개의 조치다. 다만 SSL Labs에서 좋은 등급을 받으려면 함께 꺼야 하고, PCI DSS도 TLS 1.0 사용을 금지하므로 실무에서는 같이 처리하게 된다. (TLS 1.0/1.1은 2021년 RFC 8996으로 공식 폐기되었다.)
현재 기준 권장 설정은 TLS 1.2와 1.3만 허용하는 것이다.
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
OpenSSL 1.1.0부터는 SSLv2가 아예 컴파일에서 빠졌으므로, 최신 nginx/OpenSSL을 쓰고 있다면 DROWN은 이미 해당 사항이 없다.
그렇게 설정했는데도 아무리해도 되질 않았다.
- https://serverfault.com/questions/704376/disable-tls-1-0-in-nginx
에서 답을 찾았다. default_server 설정이 있어야 한다는 것.
nginx virtualhost 설정에서
server {
listen 443 ssl default_server;
root /opt/bitnami/apps/blog.dongbumkim.com/htdocs/;
server_name blog.dongbumkim.com;
ssl_certificate /etc/letsencrypt/live/blog.dongbumkim.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/blog.dongbumkim.com/privkey.pem;
include "/opt/bitnami/nginx/conf/ssl_param.conf";
include "/opt/bitnami/apps/blog.dongbumkim.com/conf/nginx-app.conf";
}
default_server가 왜 필요했나
ssl_protocols를 고쳤는데도 반영되지 않았던 이유는 이렇다. 클라이언트가 SNI를 보내지 않거나 매칭되는 server_name이 없으면, nginx는 해당 listen 주소:포트의 기본 서버 블록의 SSL 설정을 사용한다. 테스트 도구는 SNI 없이 접속해 보는 경우가 많아, 의도치 않은 다른 블록의 설정이 적용되고 있었던 것이다.
명시적으로 default_server를 지정하지 않으면 해당 주소:포트에 대해 가장 먼저 정의된 server 블록이 기본이 된다.
정정 : default_server는 listen 주소:포트 단위다
원래 이 글에는 “default_server는 하나만 있어야 하고 여러 곳에 넣으면 에러난다”고 적었는데 정확하지 않다. default_server는 listen의 주소:포트 조합마다 하나씩 지정할 수 있다.
server {
listen 80 default_server; # 80번의 기본 서버
...
}
server {
listen 443 ssl default_server; # 443번의 기본 서버 - 문제없다
...
}
에러가 나는 것은 같은 주소:포트에 대해 두 번 이상 지정했을 때다.
nginx: [emerg] a duplicate default server for 0.0.0.0:443
SNI를 보내지 않는 클라이언트를 아예 거부하고 싶다면, 기본 서버를 따로 두고 444로 끊어버리는 방법도 많이 쓴다.
server {
listen 443 ssl default_server;
ssl_reject_handshake on; # nginx 1.19.4+
return 444;
}
SSL 설정은 다음 사이트에서도 만들 수 있다.
- https://ssl-config.mozilla.org/ (Mozilla SSL Configuration Generator)
- https://www.ssllabs.com/ssltest/ (설정 후 등급 확인)
댓글 남기기