TLS 1.3/ECH까지 한 번에 정리
title: "SNI는 왜 복호화 없이 보이나? (TLS 1.3/ECH까지 한 번에 정리)"
slug: why-sni-visible-and-what-ech-changes
series: "URL·TLS·SNI·필터링·DPI 실전 가이드"
author: EX Corp. Tech Team
summary: "SNI가 평문으로 노출되는 구조적 이유, TLS 1.2/1.3과 HTTP/2·3에서의 위치, 그리고 ECH가 등장하면 무엇이 달라지는지 실무 관점으로 설명."
tags: [TLS, SNI, ECH, HTTPS, QUIC, HTTP2, HTTP3, DPI, 필터링]
reading_time: "10~12분"
한눈에 핵심
- 왜 보이나? SNI(Server Name Indication)는 서버가 어떤 인증서를 낼지 고르도록 하려고 TLS ClientHello 확장에 평문으로 실린다. 복호화 없이도 중간 장비가 읽을 수 있음.
- 어디서 보이나? HTTP 버전(H1/H2/H3)과 무관하게 TLS 계층에서 보인다. H3(QUIC)도 초기 핸드셰이크 구간에 TLS가 올라가므로 원리는 동일.
- 뭘 못 보나? SNI(도메인) 외의 경로·쿼리·헤더·본문은 TLS 수립 이후 암호화된다.
- ECH가 오면? Encrypted ClientHello(ECH) 가 활성화되면 SNI 자체가 암호화되어 중간 장비에서 호스트명이 안 보인다. 이때는 DNS 레이어 통제(도메인 차단) 중요성이 커진다.
1) SNI의 태생적 목적: “가상호스팅을 위한 힌트”
하나의 IP에서 여러 도메인을 서비스(가상호스팅)하려면 서버는 클라이언트가 접속하려는 호스트명을 알아야 맞는 인증서를 제시할 수 있다. 문제는 인증서를 내보내기 전에 이미 어떤 인증서를 낼지 결정해야 한다는 것.
→ 그래서 클라이언트가 가장 처음 보내는 ClientHello 안에 SNI(호스트명) 를 평문으로 넣는다.
요점: SNI는 “암호화를 열기 위한 열쇠를 고르는 힌트” 이기 때문에 암호화 이전에 나와야 한다.
2) 프로토콜별 위치: H1/H2/H3와 무관, “TLS가 핵심”
- HTTP/1.1, HTTP/2: TCP 위에 TLS. ClientHello → (SNI 노출) → 핸드셰이크 완료 → 암호화된 HTTP
- HTTP/3: QUIC(UDP) 위에 TLS 1.3. QUIC의 Initial 패킷은 표준 소금(salt)으로 파생된 키로 보호되지만, TLS ClientHello의 SNI는 여전히 중간에서 판독 가능(도구가 초기 시크릿을 계산해 디섹트).
- 결론적으로 HTTP 버전과 관계없이 “SNI는 TLS 핸드셰이크의 일부”라서 복호화 없이 중간에서 읽힌다.
3) 무엇이 보이고/안 보이는가 (TLS 1.3 기준)
- 보임: IP/포트/타이밍 등 메타데이터 + ClientHello의 SNI(호스트명)
- 안 보임: 서버 인증서(1.3에선 암호화 전송), HTTP 경로/쿼리/헤더/본문
- ALPN(어떤 HTTP 버전 쓸지) 도 ClientHello 확장으로 실린다(평문). 하지만 URL 경로/쿼리는 어느 경우에도 노출되지 않는다.
4) ECH(Encrypted ClientHello): SNI의 종말? 변화 포인트
ECH의 목표는 간단하다. ClientHello 자체(특히 SNI) 를 암호화해 중간자에게 호스트명이 보이지 않게 한다.
구조(요약)
- Outer ClientHello: 겉으로 보이는 ClientHello. 여기에 진짜 목적지와 다른 “커버 이름”(예: CDN의 공개 호스트)이 들어간다.
- Inner ClientHello: 진짜 SNI 등 민감 확장이 HPKE(공개키 기반 하이브리드)로 암호화되어 담긴다.
- 서버는 DNS HTTPS RR(aka SVCB/HTTPS record) 로 배포된 ECH 구성(public key) 를 통해 이를 복호화한다.
실무 의미
- 중간 장비는 호스트명을 못 본다. 따라서 SNI 필터링은 동작하지 않거나 오탐 가능.
- DNS 레이어 통제가 중요해진다: 기업/국가 레벨에서 승인된 리졸버로 트래픽을 유도하고 DNS 정책으로 도메인을 통제.
- 점진 도입: 브라우저·OS·리졸버·CDN이 맞물려야 한다. 일부 구간은 GREASE(무작위·가짜 값 삽입) 로 중간 장비를 시험하며, 점차 보급률이 올라가는 추세.
기억할 점: ECH는 “전면 ON/ON”의 스위치가 아니라 생태계 전반의 호환이 필요한 기능이라 도메인/네트워크별로 적용/미적용이 혼재할 수 있다.
5) 필터링·관측 관점 정리(보안/네트워크 실무)
SNI 필터링이 유효한 세계
- 미적용 환경(ECH 없음):
- 도메인 단위 정책은 SNI로 가능
- 경로/쿼리 기반 정책은 불가 → 프록시 가시화(SSL Inspection)나 엔드포인트 에이전트 필요
ECH가 보급된 세계
- 도메인 가시성 상실: 중간 장비에서 호스트명 자체를 못 본다
- 대안:
- DNS 레이어 정책(카테고리/평판/허용목록)
- 엔드포인트 보안(브라우저 확장, 호스트 에이전트)
- 조직 출구 프록시라도 가시화를 강제하기 어려움(핀닝·앱 호환 문제 확대)
- 모니터링: 흐름/행위 기반(트래픽 패턴, 목적지 ASN/지리, 이상치 탐지) 비중 증가
6) 현장 체크리스트
- 우리 트래픽의 HTTP/3 비율, CDN 사용 현황, 브라우저/OS 버전 분포는?
- DNS 정책: 사내 DoH/DoT 강제/허용 여부, 승인 리졸버 우회 방지(방화벽·프록시)
- 가시화 필요 시 합법성·프라이버시·성능 이슈와 예외리스트 운영 계획(핀닝/금융/메신저 앱 등)
- SIEM 로깅: 도메인 가시성이 줄어드는 만큼 대체 지표(IP/ASN/JA3/ALPN/플로우) 수집 강화
7) 빠른 재현/실습 스니펫
macOS/리눅스 기준. (Windows는 WSL/PowerShell 대체)
1) 특정 IP로 SNI만 바꿔 접속해 보기 (서버 인증서 선택 변화 관찰)
# example.com의 A 레코드 중 하나(예시)로 직접 접속하되, SNI는 example.com으로 보냄
openssl s_client -connect 93.184.216.34:443 -servername example.com -tls1_3 </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer
2) Wireshark/tshark로 ClientHello의 SNI 확인
tshark -i any -f "tcp port 443" -Y "tls.handshake.type == 1" \
-T fields -e ip.dst -e tls.handshake.extensions_server_name | head
3) QUIC(H3)에서도 ClientHello 잡아보기
tshark -i any -f "udp port 443" -Y "quic && tls.handshake.type == 1" \
-T fields -e ip.dst -e tls.handshake.extensions_server_name | head
결과에 SNI가 안 보이면: 해당 도메인이 ECH를 쓰거나, 캡처 인터페이스가 다를 수 있음(VPN 터널
utunX등 확인).
8) TL;DR
- SNI는 인증서 선택을 위해 암호화 이전(ClientHello)에 평문으로 필요하므로 복호화 없이 보인다.
- TLS 1.3/H2/H3 어디서나 원리는 동일. 보이는 건 도메인, 안 보이는 건 경로/쿼리/본문.
- ECH가 활성화되면 SNI가 암호화되어 더 이상 중간에서 보이지 않는다 → DNS 정책·엔드포인트/행위 기반 보안의 비중이 커진다.