기록

DPI와 TLS 핸드셰이크 관측 범위

TL;DR

  • HTTPS 요청의 경로와 본문은 TLS로 암호화된다.
  • TLS 연결을 시작하는 ClientHello는 암호화되기 전 메시지다.
  • SNI는 ClientHello의 server_name 확장에 들어가며, 목적지 도메인이 평문으로 노출된다.
  • TCP segmentation은 종단 서버에는 재조립된 스트림으로 보이지만, 중간 장비에는 부분 패킷으로 보일 수 있다.
  • 수동 DPI는 트래픽을 붙잡지 못하므로 완전한 재조립보다 빠른 분류에 의존한다.

HTTPS라고 해서 중간 경로에서 아무 정보도 보이지 않는 것은 아니다. HTTP 요청 경로, 쿠키, 응답 본문은 암호화되지만, TLS 연결을 시작하는 ClientHello는 아직 암호화되기 전 메시지다. 목적지 도메인은 ClientHello 안의 SNI(Server Name Indication)에 들어간다. 하나의 IP 주소에 여러 도메인이 올라가 있을 때 서버가 어떤 인증서를 내밀지 정하려면, 클라이언트가 핸드셰이크 초반에 접속하려는 이름을 알려줘야 한다.

하나의 IP에 여러 도메인이 있는 경우
  • 203.0.113.10
  • a.example.com
  • b.example.com
  • c.example.com

서버는 HTTP Host 헤더를 보기 전에 인증서를 선택해야 한다. 그래서 도메인 이름은 TLS 확장으로 먼저 전달된다.

차단 계층

사이트 차단은 여러 계층에서 발생할 수 있다. 계층마다 볼 수 있는 정보와 사용자에게 보이는 증상이 다르다.

계층 관측 대상 증상
DNS 도메인 이름 이름이 잘못 풀리거나 응답이 없다
IP 목적지 IP TCP 연결이 성립하지 않는다
HTTP Host 헤더와 요청 경로 차단 페이지나 리다이렉트가 온다
TLS ClientHello의 SNI TCP는 붙지만 TLS 핸드셰이크 근처에서 끊긴다

DPI(Deep Packet Inspection)는 출발지와 목적지 IP만 보는 것이 아니라, 패킷 안의 프로토콜 정보를 읽어 분류한다. HTTPS에서도 ClientHello의 SNI는 분류 대상이 될 수 있다.

ClientHello와 SNI

TLS 1.3의 ClientHello 구조는 RFC 8446에 정의되어 있다. 실제 협상 정보 대부분은 extensions 안에 들어간다.

ClientHello
  • legacy_version
  • random
  • legacy_session_id
  • cipher_suites
  • legacy_compression_methods
  • extensions
  • supported_versions
  • key_share
  • server_name

server_name 확장 자체가 문자열로 들어가는 것은 아니다. TLS extension은 type-length-value 구조다. server_name의 extension type은 숫자 0이고, 그 안에 host name 값이 들어간다.

바이트 의미
00 00 extension type: server_name
00 14 extension data length
00 12 ServerNameList length
00 name type: host_name
00 0f host name length
62 6c ... host name bytes

중간 장비가 찾는 대상은 server_name이라는 문자열이 아니라, 확장 구조 안에 들어 있는 host name 바이트다.

TCP segmentation과 관측 위치

TCP는 수신자에게 순서가 맞는 바이트 스트림을 제공한다. ClientHello가 여러 TCP segment로 나뉘어도 종단 서버는 이를 재조립해 읽는다.

종단 서버가 보는 흐름
  1. segment 1ClientHello 앞부분
  2. segment 2ClientHello 뒷부분
  3. TCP 재조립완전한 ClientHello
  4. TLS 처리SNI 파싱

수동 DPI는 이 위치에 있지 않다. GoodbyeDPI 문서가 설명하는 수동 DPI는 포트 미러링이나 광 스플리터처럼 트래픽 사본을 보는 구조다. 연결의 종단이 아니므로 ACK를 보내거나 재전송을 요구할 수 없다. 종단 서버와 수동 DPI의 차이는 다음과 같다.

구분 종단 서버 수동 DPI
위치 TCP 연결의 수신자 경로 옆의 관측자
제어권 ACK, 재전송, 흐름 제어 가능 트래픽 사본 관측
판단 시점 재조립 후 처리 가능 빠르게 분류해야 함
실패 방식 TLS 스택에서 실패 분류 누락 또는 오탐

SNI 값 앞이나 중간에서 TCP segment가 나뉘면 종단 서버는 두 조각을 합쳐 host name을 읽는다. 반면 중간 장비가 첫 조각만 기준으로 분류하면 host name 전체를 얻지 못할 수 있다.

SNI가 나뉘는 경우
  1. segment 1... blocked.
  2. segment 2example
  3. 종단 서버blocked.example
  4. 부분 관측 DPIblocked.

이 차이는 암호화 강도 문제가 아니다. 같은 바이트열을 보더라도, 연결을 끝까지 쥔 쪽과 옆에서 빠르게 분류하는 쪽의 조건이 다르다.

fake packet 계열 기법

GoodbyeDPI 문서에는 segmentation 외에도 fake packet 계열 기법이 나온다. TTL이 낮거나 checksum, sequence number가 어긋난 패킷을 보내 DPI의 분류 상태를 흐리게 하는 방식이다. 이 기법이 성립하려면 종단 서버와 중간 장비가 같은 패킷을 다르게 처리해야 한다.

패킷 조건 종단 서버 중간 장비
낮은 TTL 도달하지 않음 중간 경로에서 관측 가능
잘못된 checksum TCP 스택에서 폐기 구현에 따라 분류 입력으로 볼 수 있음
어긋난 sequence 정상 스트림에서 제외 구현에 따라 흐름에 반영 가능

표준을 깨뜨려 서버를 속이는 것이 아니라, 종단과 중간 관측자의 처리 조건 차이를 이용하는 방식이다.

절차적 점검 순서

“사이트가 안 열린다”는 증상만으로 DPI를 바로 의심하면 안 된다. 먼저 어느 계층에서 실패하는지 나눠야 한다.

접속 실패 분해
  • DNS 응답 이상DNS 단계
  • TCP 연결 실패IP 차단, 라우팅, 방화벽
  • TLS 핸드셰이크 실패SNI, TLS, 중간 장비 개입
  • HTTP 응답 차단HTTP 프록시, 애플리케이션 차단

DNS 응답이 변조되어 있으면 DPI가 아니라 DNS 계층 문제다. TCP 연결 자체가 성립하지 않으면 SNI까지 가지 못한다. TCP는 붙지만 TLS 핸드셰이크 근처에서 끊기면 ClientHello와 중간 장비를 볼 수 있다.

정리

DPI와 서버의 차이는 “패킷을 읽을 수 있느냐”보다 “어느 위치에서 어떤 권한으로 읽느냐”에 가깝다. 종단 서버는 TCP 연결의 수신자라 재조립된 스트림을 읽을 수 있다. 수동 DPI는 흐름을 붙잡지 못하고 트래픽 사본을 빠르게 분류해야 한다. TCP segment 경계, fake packet, checksum, TTL 같은 조건은 이 차이를 이용한다. SNI는 TLS ClientHello에 평문으로 들어간다. 다만 그 값을 읽는 쪽이 항상 서버와 같은 방식으로 완전한 ClientHello를 얻는 것은 아니다. 차단과 우회 기법을 이해하려면 암호화 여부뿐 아니라 관측 위치와 재조립 가능성을 함께 봐야 한다.

참고