TLS 1.3은 여전히 서버 이름을 평문으로 보낸다
TLS 1.3은 핸드셰이크를 암호화하지만 SNI는 아니다. ClientHello를 읽고 진짜 ECH 수용을 확인하며 관찰자가 여전히 무엇을 볼 수 있는지 기록하라.
리스너를 TLS 1.3으로 올리면 관찰자가 읽을 수 있는 내용이 달라지지만, 버전 번호가 시사하는 만큼은 아니다. ClientHello는 여전히 어떤 암호화 협상보다도 먼저 이동하며, 일반적인 연결에서는 요청된 서버 이름이 그곳에 평문으로 남는다. Encrypted Client Hello는 그것을 숨기는 메커니즘이며, 자체 전제 조건을 가진 별도의 배포다. 어느 쪽 동작을 전제로 하든 정책을 쓰기 전에 이 네 단계를 실행하라.
핸드셰이크가 실제로 노출하는 것
TLS 1.3은 서버 인증서와 ServerHello 이후의 핸드셰이크 대부분을 암호화한다. 클라이언트가 가장 먼저 보내는 모든 것은, 키가 아직 존재하지 않기 때문에, 그 보호 밖에 있다. 서버 이름 표시는 그 첫 비행의 일부이므로, 수동적 관찰자는 아무것도 깨뜨리지 않고 여전히 그것을 읽을 수 있다.
ECH 사양(RFC 9849)은 협력하는 서버를 위해 내부 ClientHello를 암호화함으로써 이를 바꾼다. 외부 핸드셰이크는 남아 있고 네트워크가 볼 수 있는 공개 이름을 나르므로, 배포에는 중간자에게 의미 있는 외부 신원이 여전히 필요하다. 그 외부 이름이 바로 연결이 익명이 되리라 기대할 때 사람들이 놓치는 부분이다. 그것은 숨겨진 이름이 아니라 덮개 이름이며, 다른 이름과 마찬가지로 해석되고 인증되어야 한다.
이 중 어느 것도 전달 경로를 숨기지 않는다. 출발지와 목적지 주소, 포트, 패킷 크기, 타이밍은 여전히 관찰 가능하며, 이는 종종 이름보다 누가 말하는지를 더 잘 보여 준다. 이름 해석과 응용 계층의 관계는 또 다른 층이며, 각각 고유한 가시성을 가진다.
가정하지 말고 ClientHello를 읽어라
ServerHello의 버전은 클라이언트가 무엇을 보냈는지 알려 주지 않는다. 관심 있는 관찰자를 대표하는 위치에서 첫 비행을 직접 살펴보라.
openssl s_client -connect app.plant.example:443 -servername app.plant.example -tls1_3 </dev/null> 2>/dev/null | head -20 sudo tcpdump -ni eth0 -c 40 'tcp port 443' -w /tmp/tls.pcap tshark -r /tmp/tls.pcap -Y 'tls.handshake.extensions_server_name' -T fields -e tls.handshake.extensions_server_name
첫 번째 명령은 핸드셰이크를 수행하고 프로토콜 버전과 요청한 이름을 포함한 협상된 매개변수를 보여 준다. 두 번째는 실제 연결의 첫 패킷을 캡처하고, 세 번째는 그 캡처에서 SNI 필드를 추출한다. 필드가 채워져 있으면 에뮬레이션한 관찰자가 그것을 읽을 수 있다.
둘이 일치하지 않을 때는, 로컬 캡처가 나중에 중간 장비가 다시 쓰거나 버리는 이름을 보여 줄 수 있으므로, 클라이언트 쪽과 경로에서 따로 캡처하라. 종료하는 프록시는 설계상 평문을 보므로 네트워크가 보는 것에 대해 아무것도 증명하지 못하므로, TLS를 스스로 종료하지 않는 호스트에서도 캡처하라.
ECH 확장은 주장이지 증거가 아니다
ClientHello에서 ECH 확장이 보인다고 해서 그 연결이 ECH를 썼다는 뜻은 아니다. 클라이언트는 쓸 만한 구성이 없을 때, 바로 핸드셰이크가 똑같아 보이게 하기 위해 GREASE ECH를 보낸다. 확장은 있고, 내부 hello는 미끼이며, 실제 이름은 여전히 읽힌다.
dig +short HTTPS app.plant.example openssl s_client -connect app.plant.example:443 -tls1_3 -status </dev/null> 2>/dev/null | grep -i -E 'ech|status_request'
첫 번째 명령은 오리진이 ECH 구성 매개변수가 있는 HTTPS 리소스 레코드를 게시하는지 보여 주며, 클라이언트는 그렇게 키를 배운다. 두 번째는 핸드셰이크 상태 정보를 찾지만, 클라이언트의 성공 메시지가 더 강한 증거다. 중요한 것은 수용이며, 맞는 키가 없는 서버는 내부 hello를 복호화할 수 없고 연결은 물러난다.
브라우저 지원과 구성이 버전과 플랫폼에 따라 다르므로 클라이언트도 확인하라. „최신 브라우저는 ECH를 쓴다“에 기반한 정책은 어떤 함대에 대한 추측이지 당신의 함대에 대한 사실이 아니다. 실제로 연결하는 버전을 목록화하고, 각각에서 하나씩 시험하라. 현재 데스크톱 브라우저에서 동작하는 같은 페이지가 같은 네트워크의 더 오래된 클라이언트에게는 아무것도 숨기지 못할 수 있다.
관찰자의 범위를 정책에 적어라
통제가 무엇에 의존할 수 있는지 결정하기 전에 관찰자가 어디에 앉아 있고 그 지점에서 무엇이 보이는지 밝혀라. 브라우저에서 사이트로의 연결, 외부 VPN 전송, TLS를 종료하는 프록시는 각각 다른 사실 집합을 드러내며, 한 위치를 위해 쓴 규칙이 다른 위치로 깔끔하게 옮겨 가는 경우는 드물다.
통제가 SNI 읽기에 의존한다면, ECH가 있을 때와 없을 때 배포된 클라이언트가 어떻게 행동하는지 시험하라. 그다음, 조용히 일치를 멈추는 필터는 애초에 배포되지 않은 필터보다 나쁘다는 호환성 결과를 기록하라.
마지막으로 불확실성을 기록에 남겨라. 오래된 보편적 주장을 더 새로운 것으로 바꾸면 같은 틈이 다른 프로토콜 이름 아래 남을 뿐이고, 다음 검토자도 똑같이 굳게 그것을 믿을 것이다.