본문으로 건너뛰기
yutils

HTTPS 는 어떻게 안전할까? (TLS handshake)

ClientHello 와 첫 암호 byte 사이에서 무엇이 일어나는지 — certificate, cipher suite, key exchange, SNI, 그리고 TLS 1.3 가 handshake 를 2 RTT 에서 1 RTT 로 줄인 방법.

약 9분 읽기

브라우저 주소창의 자물쇠 아이콘 뒤에는 TLS handshake 가 있다. ClientHello 부터 첫 암호화 byte 까지 — 인증서 검증·키 교환·cipher 선택 등 복잡한 협상. 어떻게 두 처음 만나는 컴퓨터가 안전한 공유 비밀 을 누구도 엿듣지 못하게 만들까? 이 가이드는 TLS 1.2 와 1.3 의 handshake 과정, certificate chain, SNI, forward secrecy 의 의미를 정리한다.

TLS 가 해결하는 3 가지 문제

  • 기밀성 (Confidentiality) — 누구도 통신 내용을 읽을 수 없음 (암호화)
  • 무결성 (Integrity) — 누구도 통신 내용을 변경할 수 없음 (MAC / AEAD)
  • 인증 (Authenticity) — 상대가 진짜 그 서버인지 확인 (certificate)

평문 HTTP 는 셋 다 X. 카페 Wi-Fi 에서 누구나 보고 변조 가능.

TLS 1.2 handshake — 2 round trip

Client                              Server
  │                                    │
  │──── ClientHello ──────────────────→│   (1st RTT)
  │     · TLS version (1.2)            │
  │     · cipher suites 제안           │
  │     · random number (28 byte)      │
  │     · SNI (server name)            │
  │                                    │
  │←─── ServerHello ───────────────────│
  │     · 선택된 cipher                │
  │     · random number                │
  │←─── Certificate ───────────────────│
  │     · server certificate chain     │
  │←─── ServerKeyExchange (RSA 외)─────│
  │←─── ServerHelloDone ───────────────│
  │                                    │
  │── 1) certificate 검증             │
  │── 2) pre-master secret 생성       │
  │── 3) 서버 public key 로 암호화   │
  │                                    │
  │──── ClientKeyExchange ────────────→│   (2nd RTT)
  │──── ChangeCipherSpec ─────────────→│
  │──── Finished (encrypted) ─────────→│
  │                                    │
  │←─── ChangeCipherSpec ──────────────│
  │←─── Finished (encrypted) ──────────│
  │                                    │
  │←──── Application Data (encrypted) ─→│   (실제 통신 시작)

2 RTT 가 걸림 — 도쿄 ↔ 서울 (50ms) 면 100ms, 미국 ↔ 한국 (180ms) 면 360ms 지연. 모바일 / 위성에서 큼.

TLS 1.3 handshake — 1 round trip

Client                              Server
  │                                    │
  │──── ClientHello ──────────────────→│   (1st RTT)
  │     · TLS version (1.3)            │
  │     · key share (DHE/ECDHE) 미리   │
  │     · supported cipher suites      │
  │     · SNI                          │
  │                                    │
  │←─── ServerHello ───────────────────│
  │     · 선택된 cipher                │
  │     · server key share             │
  │     · Certificate (encrypted)      │
  │     · CertificateVerify (encrypted)│
  │     · Finished (encrypted)         │
  │                                    │
  │── certificate 검증                │
  │                                    │
  │──── Finished (encrypted) ─────────→│
  │←──── Application Data (encrypted) ─→│   (즉시 통신)

핵심 차이:

  • 1 RTT 만 — Client 가 key share 를 ClientHello 에 미리 박음
  • 0-RTT resumption — 두 번째 connection 부터는 이전 세션 key 재활용 → 0 RTT (단, replay attack 위험으로 GET 만)
  • cipher 단순화 — TLS 1.2 의 30+ cipher 옵션 → 5 개로 축소 (AES-GCM, AES-CCM, ChaCha20-Poly1305 기반)
  • forward secrecy 필수 — RSA key exchange 폐기, ephemeral DH 만

Cipher suite — 무엇이 뽑히나

TLS 1.2 형식:
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
    │     │   │    │       │    │
    │     │   │    │       │    └─ MAC 알고리즘
    │     │   │    │       └────── AEAD (Authenticated Encryption)
    │     │   │    └────────────── 대칭 암호 알고리즘
    │     │   └─────────────────── 인증 알고리즘 (RSA 서명)
    │     └─────────────────────── key exchange (Elliptic Curve DH Ephemeral)
    └───────────────────────────── 프로토콜

TLS 1.3 형식 (단순화):
TLS_AES_256_GCM_SHA384
    │     │       │
    │     │       └─ hash
    │     └───────── AEAD
    └─────────────── 프로토콜

TLS 1.3 의 cipher suite 가 단순해진 이유 — key exchange / 인증은 별도 협상 (key_share / signature_algorithms 확장). 옵션 폭주 회피.

Certificate — 서버를 누가 보증하나

서버가 보내는 certificate 는 X.509 형식:

Subject:        CN=example.com (또는 SAN: example.com, *.example.com)
Issuer:         Let's Encrypt R3
Valid:          2026-05-01 ~ 2026-08-01 (90 일)
Public Key:     -----BEGIN PUBLIC KEY----- ... (RSA 2048 또는 ECDSA P-256)
Signature:      Issuer 가 자신의 private key 로 서명
Extensions:     SAN, OCSP, CT log 등

Client 의 검증:

  1. certificate 의 hostname (CN 또는 SAN) 이 접속 도메인과 일치?
  2. 유효 기간 안?
  3. Issuer 의 서명이 valid? (Issuer 의 public key 필요)
  4. Issuer 가 trusted CA?

Certificate chain — root CA 까지

example.com cert         ← server 가 보냄
   ↑ 서명
Let's Encrypt R3 (intermediate CA)   ← server 가 함께 보냄
   ↑ 서명
ISRG Root X1 (root CA)               ← Client OS / 브라우저에 미리 박힘

OS / 브라우저가 약 200 개 root CA 의 public key 를 trust store 에 보유. Mozilla / Apple / Microsoft 가 매년 업데이트.

SNI — 한 IP 의 여러 사이트

옛 (SNI 없음):
Client → 203.0.113.5:443 → "Hello"
Server: 어떤 site 의 cert 를 보내야 할지 모름

SNI (Server Name Indication):
Client → 203.0.113.5:443 → "Hello, host=example.com"
Server: example.com 의 cert 선택해서 보냄

ClientHello 의 SNI extension. CloudFlare / AWS / Cloudfront 같은 shared hosting 에 필수. 그러나 평문 노출 — 어느 사이트 방문하는지 ISP 가 봄.

ESNI / ECH (Encrypted Client Hello) — TLS 1.3 의 SNI 도 암호화. Cloudflare 가 default 활성. 도입 진행 중.

Forward Secrecy — 미래의 비밀

과거 RSA key exchange — server 의 private key 가 유출되면 과거 모든 통신을 디크립트 가능. 정보 보안의 큰 위험.

Forward Secrecy = ephemeral key — handshake 마다 새 임시 key 생성, handshake 후 폐기. private key 유출돼도 과거 통신 안전.

DHE  (Diffie-Hellman Ephemeral)
ECDHE (Elliptic Curve DHE) — 현재 표준, 더 빠름

핵심:
1. Client 와 Server 가 각자 ephemeral private/public key 생성
2. public key 교환
3. 양쪽이 동일한 shared secret 도출 (수학 trick — 도청자는 불가)
4. handshake 후 ephemeral private key 폐기

TLS 1.3 는 ECDHE 만 허용. RSA key exchange 폐기.

Mutual TLS (mTLS) — 서버도 client 검증

표준 TLS:
- Client 가 server cert 검증

mTLS:
- Server 가 client cert 도 요구
- 둘 다 cert + private key 보유
- 양방향 인증

사용처:

  • Service-to-service authentication (Kubernetes service mesh)
  • API gateway 의 client 인증 (password 대신)
  • Banking / 금융 API

HSTS — HTTP downgrade 방지

HTTP/2 응답 header:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

→ 1 년간 이 도메인은 HTTPS 만 (브라우저 강제)
→ http://example.com 자동 HTTPS 로 redirect (브라우저 안)
→ certificate 에러 시 클릭 우회 불가

preload — Chrome / Firefox 의 hardcoded HSTS list 에 사이트 추가. 가장 강력. 한 번 가입하면 빠지기 어려움.

흔한 함정

1. expired certificate

Let's Encrypt 가 90 일 (짧음). 자동 renewal 안 되면 사이트 다운. certbot / Caddy 의 자동 갱신 권장.

2. mixed content

<!-- HTTPS page 안 -->
<img src="http://insecure.com/logo.png">
→ 브라우저 차단 또는 경고 (mixed content)

3. weak cipher suite

TLS 1.0 / 1.1 / 3DES / RC4 가 아직 server config 에 있으면 약함.nmap --script ssl-enum-ciphers -p 443 example.com 또는 SSL Labs 로 점검.

4. SNI 누락

curl, Java 옛 버전, Python 2 — SNI 없이 요청 → server 가 default site 응답 → certificate 불일치.

5. intermediate certificate 누락

Server 가 intermediate CA cert 를 함께 보내지 않으면 client 의 chain 검증 실패. browser 는 missing intermediate 자동 fetch 가능하지만 일부 클라이언트는 안 함.

참고 자료

요약

  • TLS 는 기밀성 + 무결성 + 인증 3 가지. 평문 HTTP 는 셋 다 X.
  • TLS 1.2 = 2 RTT handshake. TLS 1.3 = 1 RTT + 0-RTT resumption.
  • Cipher suite — key exchange · 인증 · AEAD · hash 조합. TLS 1.3 가 단순화.
  • Certificate chain — server cert → intermediate CA → root CA ( OS trust store).
  • SNI = 한 IP 의 여러 사이트 구분. 평문 노출, ECH 가 암호화.
  • Forward Secrecy = ephemeral key. private key 유출돼도 과거 통신 안전. TLS 1.3 필수.
  • mTLS = 양방향 인증. service mesh / API gateway 에 사용.
  • HSTS = HTTPS 강제. preload 가 가장 강력.
  • 실험 — HMAC 생성기 (TLS 내부 MAC 알고리즘 이해) / cURL 빌더 (curl 의 -v 로 wire trace).
가이드 목록으로