본문 바로가기

IT와 과학

TLS 보안 완벽 가이드: 취약점 제거부터 실전 설정까지

728x90
반응형

TLS 보안 완벽 가이드: 취약점 제거부터 실전 설정까지

TL;DR: TLS 1.0/1.1과 약한 암호화 스위트를 완전히 제거하고, TLS 1.2/1.3만 사용하는 것이 2025년 현재 보안의 기본입니다. 이 가이드에서는 이론부터 실전 설정까지 모든 것을 다룹니다.


들어가며

최근 몇 년간 TLS 관련 보안 이슈가 지속적으로 발견되면서, 많은 조직에서 TLS 설정을 재검토하고 있습니다. 특히 Azure Application Gateway의 TLS 1.0/1.1 지원 종료(2025년 8월 31일) 발표는 많은 개발팀에게 시급한 과제가 되었죠.

오늘은 TLS가 무엇인지부터 시작해서, 어떤 버전과 설정이 취약한지, 그리고 실제 운영 환경에서 어떻게 보안을 강화할 수 있는지까지 체계적으로 알아보겠습니다.


TLS란 무엇인가?

**TLS(Transport Layer Security)**는 인터넷에서 클라이언트와 서버 간 통신을 보호하는 프로토콜입니다. 세 가지 핵심 기능을 제공합니다:

  • 기밀성(Confidentiality): 데이터를 암호화하여 제3자가 볼 수 없게 함
  • 무결성(Integrity): 데이터가 전송 중 변조되지 않았음을 보장
  • 인증(Authentication): 서버(및 선택적으로 클라이언트)의 신원을 확인

현재 최신 버전은 TLS 1.3이며, 이전 버전 대비 설계가 단순해지고 보안이 크게 향상되었습니다.


TLS는 어디에 사용되나?

TLS는 우리가 매일 사용하는 거의 모든 인터넷 서비스에서 활용됩니다:

  • 웹 브라우징: HTTPS (HTTP over TLS)
  • 이메일: SMTP/IMAP/POP의 STARTTLS
  • API 통신: REST API, GraphQL 등
  • 데이터베이스: MySQL, PostgreSQL 등의 암호화 연결
  • 메시징: Slack, Teams 등의 실시간 통신

TLS 버전별 현황: 무엇을 써야 하나?

🚫 폐기된 버전 (절대 사용 금지)

  • SSLv2/SSLv3: 심각한 보안 취약점으로 완전 폐기
  • TLS 1.0/1.1: RFC 8996에서 공식 폐기 선언

✅ 권장 버전

  • TLS 1.2: 현재 가장 널리 사용되며 안전한 버전
  • TLS 1.3: 최신 버전으로 성능과 보안이 크게 개선됨

미국 NIST 가이드라인에서도 TLS 1.2를 필수로, TLS 1.3 도입을 권장하고 있습니다.


암호화 스위트: 안전한 것과 위험한 것

TLS 1.3 권장 스위트

TLS 1.3에서는 스위트가 크게 단순화되었습니다:

  • TLS_AES_128_GCM_SHA256
  • TLS_AES_256_GCM_SHA384
  • TLS_CHACHA20_POLY1305_SHA256

TLS 1.2 권장 조합

ECDHE + (AES-GCM 또는 ChaCha20-Poly1305) 조합을 사용하세요:

  • ECDHE-ECDSA-AES128-GCM-SHA256
  • ECDHE-RSA-CHACHA20-POLY1305

🔴 반드시 제거해야 할 취약 요소

프로토콜 레벨:

  • SSLv2/3, TLS 1.0, TLS 1.1

암호화 스위트:

  • RC4, 3DES/DES, NULL/aNULL/EXPORT/LOW
  • 정적 RSA 키교환, 익명 DH
  • MD5, SHA-1 서명
  • 약한 DH (<2048비트)
  • 구식 CBC 조합

키 길이 권장사항:

  • RSA: 최소 2048비트 (가급적 3072비트)
  • ECDSA: P-256/P-384
  • DH 파라미터: 최소 2048비트
  • 곡선: X25519 또는 secp256r1 우선

핵심 질문: 서버만 설정하면 될까, 양쪽 다 해야 할까?

완전히 안전·준수하려면 "양쪽 모두"에서 제거(차단)하는 게 정석입니다. 다만 "한쪽만" 바꿔도 그 쪽으로 들어오는 트래픽은 강제로 안전한 스펙으로 협상되거나 실패하므로, 해당 방향은 보호됩니다.

언제 한쪽만으로도 되나?

A 서버(수신자)만 TLS 1.2/1.3로 제한하면 B→A 연결은 약한 프로토콜/암호로는 협상이 안 됩니다(강한 걸로 올라가거나 실패). → A 쪽 수신 방향 보안은 확보됩니다.

왜 양쪽 다 해야 하나?

  1. 양방향 연동(서로 요청/응답을 보냄)이라면, A가 발신자가 되는 순간 A의 클라이언트 스택(JDK/SChannel/OpenSSL) 정책이 약하면, 다른 서버가 약한 걸 허용할 때 약한 걸로 내려가 협상할 수 있습니다.
  2. LB/프록시/게이트웨이가 TLS를 종료한다면 그 지점에서도 정책을 걸어야 합니다. (프런트단과 백엔드단이 분리되면 두 구간 모두 적용)
  3. 컴플라이언스(내부 규정/감사) 관점에선 "엔드투엔드"로 약한 스펙을 어디서도 허용하지 않음이 요구되는 경우가 많습니다.

🎯 빠른 결정표

  • 단방향 호출(B→A만 호출) + A만 강화 ⇒ B→A는 안전(또는 실패)
  • 양방향 호출A/B 둘 다 "수신(서버 설정)"과 "발신(클라이언트 정책)"에 동일 기준 적용
  • LB/AGW/ALB 등 종단이 여러 개종단마다 최소 TLS 1.2/1.3, 약한 스위트 차단

실전 설정: 플랫폼별 취약점 제거 방법

1. Linux 시스템 전역 정책 (RHEL 계열)

RHEL 8/9는 시스템 전역 암호화 정책으로 한 번에 설정할 수 있습니다:

# SHA-1까지 차단
sudo update-crypto-policies --set DEFAULT:NO-SHA1

# 더 엄격한 설정 (호환성 검토 후 적용)
sudo update-crypto-policies --set FUTURE

설정 후 재부팅이 필요하며, 개별 애플리케이션 설정도 함께 확인해야 합니다.

2. NGINX 설정

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
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';
ssl_ecdh_curve X25519:P-256:P-384;

# 추가 보안 헤더
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

3. Apache httpd 설정

SSLProtocol             TLSv1.2 TLSv1.3
SSLCipherSuite          HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!RC4:!MD5:!SHA1:!PSK:!SRP:!DSS
TLS13CipherSuites       TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
SSLHonorCipherOrder     on
SSLOpenSSLConfCmd       Curves X25519:P-256:P-384

4. Java/Tomcat 설정

Tomcat Connector 설정:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
           SSLEnabled="true"
           sslProtocol="TLS"
           sslEnabledProtocols="TLSv1.3,TLSv1.2"
           ciphers="TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
                    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
                    TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"/>

Java 전역 차단 설정 (java.security):

jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, RC4, DES, 3DES_EDE_CBC,
  MD5withRSA, DH keySize < 2048, EC keySize < 224, SHA1 jdkCA, RSA keySize < 2048, ECDH

5. Windows/IIS 설정

레지스트리를 통해 TLS 1.0/1.1을 비활성화할 수 있습니다:

HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server
  Enabled=0 (DWORD)
  DisabledByDefault=1 (DWORD)

⚠️ 주의: 레지스트리 변경은 시스템 전체에 영향을 미치므로 충분한 테스트 후 적용하세요.

6. WildFly/JBoss 설정

Elytron 보안 컨텍스트에서 설정:

<server-ssl-context name="httpsSSC"
    protocols="TLSv1.3 TLSv1.2"
    cipher-suite-filter="TLS_ECDHE_.*_(AES|CHACHA20)_.*GCM_.*"
    key-manager="serverKM" trust-manager="serverTM"/>

7. 클라우드 로드밸런서 설정

Azure Application Gateway:

az network application-gateway ssl-policy set \
  -g <RG> --gateway-name <AGW> \
  --policy-type Predefined --name AppGwSslPolicy20220101S \
  --min-protocol-version TLSv1_2

중요한 변화: Azure Application Gateway는 2025년 8월 31일부터 TLS 1.0/1.1 지원을 완전히 중단합니다. 백엔드 서버도 최소 TLS 1.2 이상으로 준비해야 합니다.

AWS ALB: 보안 정책을 ELBSecurityPolicy-TLS-1-2-Ext-2018-06 또는 그 이상으로 설정하세요.


설정 검증: 제대로 적용되었는지 확인하기

외부 서비스 검증

SSL Labs 테스트 (가장 간편):

https://www.ssllabs.com/ssltest/

내부/사설망 검증

nmap 스크립트:

nmap -p 443 --script ssl-enum-ciphers <host>

testssl.sh (권장):

./testssl.sh -p 443 <host>

🔍 실무 검증 체크리스트

약한 연결 시도가 실패하는지 확인:

# TLS 1.0 시도 → 실패해야 정상
openssl s_client -connect host:443 -tls1_0

# TLS 1.1 시도 → 실패해야 정상  
openssl s_client -connect host:443 -tls1_1

강한 연결 시도가 성공하는지 확인:

# TLS 1.2 시도 → 성공해야 정상
openssl s_client -connect host:443 -tls1_2

# TLS 1.3 시도 → 성공해야 정상
openssl s_client -connect host:443 -tls1_3

양방향 통신 환경에서는 상호 방향 모두 점검:

  • A→B 방향과 B→A 방향 각각 테스트
  • 클라이언트 정책과 서버 정책 모두 확인

실무 완전 체크리스트

📋 프로토콜 및 암호화 정책

  • [ ] 프로토콜: 양쪽(및 LB) 모두 TLS 1.2/1.3만 허용, 1.0/1.1/SSLv3 끄기
  • [ ] 암호 스위트: **ECDHE + (AES-GCM/ChaCha20)**만, RC4/3DES/CBC/MD5/SHA-1/익명DH/정적RSA 키교환 제거
  • [ ] 클라이언트 정책: JDK라면 java.security의 jdk.tls.disabledAlgorithms에 약한 항목 추가(발신도 통제)
  • [ ] LB/게이트웨이: 프런트/백엔드 두 구간 모두 최소버전과 스위트 정책 지정

🔄 양방향 통신 고려사항

  • [ ] 서버 설정: 수신 연결에 대한 TLS 정책 적용
  • [ ] 클라이언트 설정: 발신 연결에 대한 TLS 정책 적용
  • [ ] 상호 연결 테스트: A↔B 양방향 모두 약한 프로토콜 차단 확인
  • [ ] 프록시/LB 구간: 각 TLS 종료 지점마다 동일한 보안 기준 적용

🧪 테스트 및 검증

  • [ ] 약한 시도 실패: openssl s_client -tls1_0/-tls1_1 실패 확인
  • [ ] 강한 시도 성공: openssl s_client -tls1_2/-tls1_3 성공 확인
  • [ ] 도구 활용: testssl.sh/nmap --script ssl-enum-ciphers로 종합 점검
  • [ ] SSL Labs: A+ 등급 달성 (외부 노출 서비스)

적용 로드맵: 안전한 마이그레이션 전략

1단계: 현황 파악

  • 모든 TLS 서비스 인벤토리 작성
  • SSL Labs, nmap, testssl.sh로 현재 상태 스캔
  • 레거시 클라이언트 식별

2단계: 스테이징 환경 적용

  • 테스트 환경에서 새 설정 적용
  • 주요 클라이언트(브라우저, 모바일 앱, API 클라이언트) 호환성 테스트

3단계: 점진적 프로덕션 적용

  • 트래픽이 적은 시간대에 적용
  • 모니터링 도구로 연결 실패율 추적
  • 롤백 계획 준비

4단계: 레거시 지원 전략

  • 구형 클라이언트를 위한 별도 엔드포인트 고려
  • 단계적 지원 중단 일정 수립

빠른 체크리스트

설정 완료 후 다음 항목들을 확인해보세요:

  • [ ] 프로토콜: TLS 1.2/1.3만 허용 (1.0/1.1/SSL 완전 차단)
  • [ ] 암호화 스위트: TLS 1.3 기본 3종, TLS 1.2는 ECDHE + AEAD 조합만
  • [ ] 키 및 서명: RSA≥2048, ECDSA P-256/384, SHA-256/384 이상
  • [ ] 시스템 정책: OS 레벨 crypto-policies 적용
  • [ ] 웹서버/앱서버: 각 플랫폼별 설정 완료
  • [ ] 로드밸런서: 클라우드 LB 정책 업데이트
  • [ ] 양방향 통신: 서버/클라이언트 정책 모두 적용
  • [ ] 검증 완료: SSL Labs A+ 등급 또는 테스트 도구 PASS

환경별 맞춤 설정이 필요하신가요?

현재 환경(예: Java 17 / WildFly 27 / Azure Application Gateway)에 맞는 A↔B 양방향LB 프런트/백엔드에 적용할 구체적인 설정값이 필요하시다면, 댓글로 다음 정보를 알려주세요:

  • 구성 정보: 누가 누구를 호출하는지 (단방향/양방향)
  • TLS 종료 지점: 로드밸런서, 프록시, 서버 등
  • OS/미들웨어 버전: RHEL 8, Java 17, WildFly 27 등
  • 클라우드 환경: Azure AGW, AWS ALB 등

바로 복사해서 사용할 수 있는 설정 파일을 만들어드리겠습니다!


마치며

TLS 보안 강화는 한 번에 끝나는 작업이 아닙니다. 새로운 취약점이 발견되고 표준이 업데이트되면서 지속적인 관리가 필요합니다.

특히 2025년에는 여러 클라우드 제공업체와 브라우저에서 TLS 1.0/1.1 지원을 완전히 중단할 예정이므로, 지금이 바로 TLS 설정을 점검하고 업그레이드할 때입니다.

혹시 특정 환경(예: Java 17 + WildFly 27 + Azure Application Gateway)에 맞는 상세한 설정이 필요하시다면, 댓글로 알려주세요. 바로 복사해서 사용할 수 있는 설정 파일을 만들어드리겠습니다!


참고 자료

이 포스트가 도움이 되셨다면 공유해주세요! 🔒

 

728x90
반응형