HTTPS와 TLS의 실제 동작 원리: 단계별 가이드
브라우저에서 자물쇠 아이콘을 보고 연결이 안전하다고 가정해 본 적이 있을 것입니다. 하지만 HTTPS 사이트를 방문할 때 실제로 무슨 일이 일어날까요? 브라우저는 어떻게 자신이 진짜 서버와 통신하고 있고 사칭자가 아니라는 것을 알 수 있을까요? 그리고 TLS가 때때로 사이트 속도를 저하시키는 이유는 무엇일까요?
이 가이드에서는 핸드셰이크를 단계별로 살펴보며 HTTPS와 TLS의 미스터리를 풀어보겠습니다. 인증서의 역할, 대칭 및 비대칭 암호화, 그리고 자신의 프로젝트에서 TLS를 검증하고 최적화하는 방법을 배우게 될 것입니다.
HTTPS와 TLS가 실제로 하는 일
HTTPS는 TLS(전송 계층 보안) 위에 계층화된 HTTP입니다. TLS는 세 가지 보장을 제공합니다:
- 기밀성: 데이터가 암호화되어 도청자가 읽을 수 없습니다.
- 무결성: 전송 중에 데이터가 탐지되지 않고 수정될 수 없습니다.
- 인증: 공격자가 아닌 합법적인 서버와 통신하고 있습니다.
TLS가 없으면 HTTP 트래픽은 평문으로 전송됩니다. 네트워크 경로에 있는 누구든(Wi-Fi 핫스팟, ISP, 손상된 라우터) 읽거나 변경할 수 있습니다. TLS는 HTTP 데이터가 교환되기 전에 보안 채널을 설정하여 이 문제를 해결합니다.
TLS 핸드셰이크: 단계별
핸드셰이크는 마법이 일어나는 곳입니다. 공유 키를 설정하고 신원을 확인하는 협상입니다. 다음은 TLS 1.2 및 1.3(오늘날 접하게 될 두 버전)의 간략한 흐름입니다.
1단계: 클라이언트 헬로
클라이언트(브라우저)는 다음을 포함하는 ClientHello 메시지를 보냅니다:
- 지원되는 TLS 버전(예: TLS 1.3, TLS 1.2)
- 지원되는 암호화 스위트(알고리즘 조합)
- 임의의 바이트 문자열(클라이언트 랜덤)
- TLS 1.3의 경우 Diffie-Hellman 교환을 위한 키 공유
2단계: 서버 헬로 및 인증서
서버는 ServerHello(선택된 버전, 암호화 스위트, 서버 랜덤)와 인증서로 응답합니다. 인증서에는 서버의 공개 키가 포함되어 있으며 인증 기관(CA)이 서명합니다.
클라이언트는 인증서를 확인합니다: 만료되었는지? 신뢰할 수 있는 CA에서 발급했는지? 도메인이 일치하는지? 그렇지 않으면 브라우저는 경고를 표시합니다.
3단계: 키 교환
서버의 공개 키(또는 Diffie-Hellman 매개변수)를 사용하여 클라이언트와 서버는 공유 프리마스터 시크릿을 도출합니다. TLS 1.3에서는 임시 Diffie-Hellman(ECDHE)으로 수행되어 순방향 비밀성을 제공합니다: 서버의 개인 키가 나중에 손상되더라도 과거 세션은 안전하게 유지됩니다.
4단계: 완료
양측은 새로 도출된 키로 암호화된 Finished 메시지를 보냅니다. 복호화에 성공하면 핸드셰이크가 완료됩니다. 그 후 모든 애플리케이션 데이터(HTTP)는 대칭 암호화(예: AES-GCM 또는 ChaCha20-Poly1305)로 암호화됩니다.
TLS 1.3 개선 사항
TLS 1.3은 핸드셰이크를 1회 왕복(1-RTT)으로 줄이고 재방문자를 위한 0-RTT 재개를 지원합니다. 또한 구식 알고리즘을 제거하여 더 빠르고 안전합니다. 대부분의 최신 브라우저와 서버는 TLS 1.3을 지원합니다.
TLS의 대칭 vs 비대칭 암호화
TLS는 합당한 이유로 두 가지 유형의 암호화를 모두 사용합니다:
- 비대칭(공개 키) 암호화: 핸드셰이크 중에 서버를 인증하고 키를 안전하게 교환하는 데 사용됩니다. 계산 비용이 많이 들지만 키 분배 문제를 해결합니다.
- 대칭 암호화: 핸드셰이크 후 대량 데이터 전송에 사용됩니다. 빠르고 효율적입니다.
이 하이브리드 접근 방식은 공개 키 암호화의 보안성과 대칭 암호의 성능을 모두 제공합니다.
인증서: 신뢰의 닻
인증서는 공개 키를 도메인 이름에 바인딩하고 CA가 서명합니다. 브라우저와 운영 체제는 신뢰할 수 있는 루트 CA 저장소와 함께 제공됩니다. 서버가 인증서를 제시하면 클라이언트는 신뢰할 수 있는 루트까지 신뢰 체인을 구축합니다.
인증서는 수명이 제한되어 있습니다(현재 Let's Encrypt의 경우 종종 90일). 만료된 인증서는 브라우저 오류를 일으키므로 갱신을 자동화하세요.
실습: OpenSSL로 TLS 검사하기
openssl 명령줄 도구를 사용하여 서버의 TLS 구성을 검사할 수 있습니다. 이는 핸드셰이크 실패를 디버깅하거나 암호화 스위트를 확인하는 데 도움이 됩니다.
openssl s_client -connect example.com:443 -servername example.com -tls1_3
이 명령은 서버에 연결하여 인증서 체인, 협상된 암호, 세션 세부 정보를 출력합니다. 인증서가 유효한지 확인하려면 Verify return code: 0 (ok)를 찾으세요.
인증서 만료를 확인하려면:
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates
일반적인 TLS 함정과 피하는 방법
- 만료된 인증서: 자동 갱신 및 모니터링을 설정하세요. Let's Encrypt의 경우 Certbot과 같은 도구를 사용하세요.
- 혼합 콘텐츠: HTTPS 페이지에서 HTTP 리소스를 로드하면 보안이 깨집니다. 상대 URL을 사용하거나 모든 리소스가 HTTPS인지 확인하세요.
- 약한 암호화 스위트: 구식 프로토콜(TLS 1.0, 1.1)과 약한 암호(RC4, 3DES)를 비활성화하세요. TLS 1.3을 활성화하세요.
- HSTS 누락: 향후 방문에 HTTPS를 강제하려면
Strict-Transport-Security헤더를 추가하세요. - 불완전한 인증서 체인: 일부 서버는 중간 인증서를 포함하는 것을 잊어 일부 클라이언트에서 오류를 일으킵니다. SSL Labs를 사용하여 테스트하세요.
TLS 성능 최적화
TLS는 핸드셰이크로 인해 지연 시간을 추가합니다. 최소화하는 방법은 다음과 같습니다:
- 더 빠른 핸드셰이크를 제공하는 TLS 1.3을 활성화하세요.
- 세션 재개(세션 티켓 또는 사전 공유 키)를 사용하여 재방문자의 전체 핸드셰이크를 피하세요.
- OCSP 스테이플링을 활성화하여 인증서 유효성 검사 지연 시간을 줄이세요.
- 엣지에서 TLS 종료를 수행하는 CDN을 사용하여 왕복 시간을 줄이세요.
- 인증서를 작게 유지하세요(가능하면 RSA 대신 ECDSA 사용).
자주 묻는 질문
HTTPS와 TLS의 차이점은 무엇인가요?
HTTPS는 HTTP의 보안 버전이고 TLS는 보안을 제공하는 암호화 프로토콜입니다. HTTPS는 TLS를 사용하여 연결을 암호화하고 인증합니다.
TLS는 어떻게 순방향 비밀성을 제공하나요?
순방향 비밀성은 서버의 개인 키가 손상되더라도 과거 세션 키를 도출할 수 없도록 보장합니다. TLS 1.3 및 최신 TLS 1.2 구성에서 임시 Diffie-Hellman 키 교환(ECDHE)을 사용하여 달성됩니다.
일부 사이트에서 인증서 오류가 표시되는 이유는 무엇인가요?
인증서 오류는 일반적으로 인증서가 만료되었거나, 자체 서명되었거나, 다른 도메인에 발급되었거나, 인증서 체인이 불완전함을 의미합니다. 브라우저는 중간자 공격으로부터 사용자를 보호하기 위해 이러한 인증서를 거부합니다.
TLS 연결을 검사하거나 디버깅해야 할 때 Timestamp Converter와 같은 도구를 사용하면 인증서 유효 기간을 해독하고 시간 관련 문제를 디버깅하는 데 도움이 됩니다.