HTTPS와 TLS의 실제 동작 원리: 핸드셰이크 완벽 해설

Security2026-11-06TryQuickToolBox

URL 앞에 https://를 입력하고 자물쇠 아이콘을 보고 넘어갔을 것입니다. 하지만 새벽 2시에 인증서가 만료되거나, 혼합 콘텐츠 경고로 결제 페이지가 깨지거나, 고객이 API 호출이 TLS 오류로 실패하는 이유를 물어볼 때 "자물쇠는 안전하다는 뜻이에요"라는 답변은 더 이상 유용하지 않습니다. 이 글에서는 HTTPS 연결 시 실제로 네트워크 상에서 무슨 일이 일어나는지, 그리고 추측 없이 올바르게 설정하는 방법을 설명합니다.

HTTPS가 HTTP에 추가하는 것

HTTPS는 TLS(전송 계층 보안) 세션 안에서 전달되는 일반 HTTP입니다. TLS는 세 가지 구체적인 보장을 제공합니다:

이 목록에 없는 것에 주목하세요: HTTPS는 서버가 신뢰할 수 있는지, 애플리케이션에 취약점이 있는지, 데이터가 저장 시 안전한지에 대해서는 아무것도 말하지 않습니다. 파이프를 보호할 뿐, 엔드포인트를 보호하지는 않습니다.

TLS 핸드셰이크, 단계별로

핸드셰이크는 HTTP 바이트가 흐르기 전에 이루어지는 협상입니다. TLS 1.3에서는 한 번의 왕복이면 되고, TLS 1.2는 두 번 필요합니다. TLS 1.3 흐름을 쉽게 설명하면 다음과 같습니다:

  1. ClientHello — 클라이언트가 지원하는 TLS 버전, 암호화 스위트 목록, 랜덤 논스, 그리고 Diffie-Hellman 키 교환(일반적으로 X25519)을 위한 키 셰어를 보냅니다.
  2. ServerHello — 서버가 버전과 암호화 스위트를 선택하고, 자체 키 셰어를 반환하며, 인증서 체인과 핸드셰이크 트랜스크립트에 대한 서명을 보냅니다.
  3. 키 유도 — 양측이 Diffie-Hellman 교환에서 공유 비밀을 계산합니다. 임시 키를 사용하므로 세션 키가 고유하고 순방향 비밀성이 유지됩니다: 나중에 서버의 장기 키가 손상되어도 기록된 트래픽을 복호화할 수 없습니다.
  4. Finished — 양측이 트랜스크립트에 대한 MAC을 보냅니다. 무언가 변경되었다면 핸드셰이크가 중단됩니다.
  5. 애플리케이션 데이터 — HTTP 요청과 응답이 공유 비밀에서 파생된 대칭 키로 암호화됩니다.

인증서는 인증이 이루어지는 곳입니다. 서버는 개인 키로 핸드셰이크에 서명하고, 클라이언트는 인증서의 공개 키를 사용해 해당 서명을 검증한 다음, 신뢰할 수 있는 루트 CA에 대해 인증서 자체를 검증하며 호스트 이름, 유효 기간, 폐기 상태를 확인합니다.

대칭 vs 비대칭: 둘 다 사용하는 이유

비대칭 암호화(RSA 또는 ECDSA)는 느리지만 키 분배 문제를 해결합니다. 대칭 암호(AES-GCM, ChaCha20-Poly1305)는 빠르지만 공유 키가 필요합니다. TLS는 핸드셰이크 중에만 비대칭 암호화를 사용해 대칭 세션 키를 설정한 다음, 해당 키로 대량 데이터를 암호화합니다. 이것이 현대 TLS 1.3 연결이 빠른 이유입니다: 한 번의 왕복 후 나머지 모든 것에 저렴한 AES 또는 ChaCha20을 사용합니다.

암호화 스위트와 실제로 중요한 것

암호화 스위트는 알고리즘의 명명된 묶음입니다. TLS 1.3에서는 목록이 짧고 모든 옵션이 안전한 것으로 간주되지만, TLS 1.2에서는 신중하게 선택해야 합니다. 간단한 비교:

측면TLS 1.2TLS 1.3
핸드셰이크 왕복2회 (또는 재개 시 1회)1회 (재개 시 0-RTT)
키 교환RSA 또는 (EC)DHE임시 (EC)DHE만
순방향 비밀성선택 사항항상
레거시 암호 (CBC, RC4)잘못 설정하면 가능제거됨

실용적인 요점: TLS 1.2와 1.3만 활성화하고, TLS 1.0/1.1은 비활성화하며, 핸드셰이크 비용을 줄이려면 ECDSA 인증서를 선호하세요. 서버나 리버스 프록시가 스위트 순서를 선택하도록 하세요; 2024년대 소프트웨어의 대부분 기본값은 합리적입니다.

실제 연결을 검사하는 방법

문서를 믿을 필요 없이 자신의 엔드포인트를 확인하세요. openssl s_client는 협상된 버전, 암호, 인증서 체인을 보여줍니다:

openssl s_client -connect example.com:443 -servername example.com -tls1_3 </dev/null

Protocol 및 Cipher 줄을 확인한 다음, 인증서 체인 출력에서 만료 및 SAN 항목을 확인하세요. 체인이 불완전하면 일부 클라이언트는 실패하지만 브라우저는 성공할 수 있으며, 이는 "Chrome에서는 되는데 curl에서는 안 된다"는 버그의 전형적인 원인입니다.

흔한 HTTPS 잘못된 설정

합리적인 서버 설정

Nginx의 경우 최소한의 현대적인 블록은 다음과 같습니다:

server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}

fullchain.pem 파일이 중간 인증서 누락 문제를 방지합니다. ACME 챌린지를 위해 HTTP가 계속 작동하도록 포트 80에서의 리디렉션을 별도의 서버 블록에 유지하세요.

HTTPS가 보호하지 않는 것

요청이 서버에 도달하면 TLS는 끝납니다. 인젝션 결함, 잘못된 접근 제어, 로그에 유출된 비밀, 잘못 구성된 CORS는 모두 전송 계층 위에 존재합니다. TLS를 보안 프로그램이 아닌 기준선으로 취급하세요. 사고를 디버깅할 때는 전송 문제(핸드셰이크 실패, 만료된 인증서)와 애플리케이션 문제(500 오류, 잘못된 페이로드)를 초기에 분리하세요 — 해결 방법이 완전히 다릅니다.

FAQ

HTTPS는 URL 경로와 쿼리 문자열을 암호화하나요?

예. HTTPS에서는 경로와 쿼리 문자열을 포함한 전체 HTTP 요청이 암호화된 TLS 레코드 안에 있습니다. 그러나 호스트 이름(SNI)과 대상 IP는 Encrypted Client Hello를 사용하지 않는 한 핸드셰이크 중에 노출됩니다.

TLS 1.3이 항상 TLS 1.2보다 빠른가요?

일반적으로 그렇습니다. 왕복을 절약하고 0-RTT 재개를 지원하기 때문입니다. 지연이 높은 연결에서는 차이가 눈에 띄지만, 로컬 네트워크에서는 미미합니다. 더 큰 이점은 TLS 1.3이 레거시 암호 옵션을 완전히 제거한다는 것입니다.

HTTP를 HTTPS로 리디렉션하면 HSTS가 여전히 필요한가요?

예. 리디렉션은 브라우저가 서버에 도달한 후에만 도움이 됩니다. HSTS는 브라우저에게 향후 요청에 대해 HTTP를 완전히 건너뛰라고 지시하여 첫 요청이 가로채질 수 있는 창을 닫습니다.

배포를 감사하면서 인증서 세부 정보를 확인하거나 캡처된 핸드셰이크를 빠르게 디코딩해야 할 때는 터미널 기반 워크플로를 준비하세요 — 그리고 팀을 위해 결과를 문서화하는 경우, Markdown 편집기는 원시 openssl 출력을 읽기 쉬운 보고서로 바꾸는 빠른 방법입니다.