WhatsApp — 체크 두 개가 켜지기까지
메시지 하나가 X3DH 세션 수립부터 Double Ratchet 암호화, client-fanout, 기기별 큐(store-and-forward), 그리고 체크 표시 3단계(sent/delivered/read)까지 지나는 전 경로를 19단계로 따라간다 — 오프라인 큐 대기, 그룹 Sender Keys, 새 기기 연결까지.
단계 목록 · 키보드 ←/→ 이동, Space 재생
출처: WhatsApp Security Whitepaper · Meta Engineering — WhatsApp multi-device · Signal Protocol 문서 (X3DH · Double Ratchet)
WhatsApp 서버는 메시지 내용을 한 번도 읽지 못한 채 전달만 책임진다 — 암호화는 발신 기기가 수신 기기별로 하고, 서버는 기기별 큐에 암호문을 잠시 맡았다가 전달 즉시 지우며, 체크 표시가 그 경로의 이정표다.
왜 헷갈리는가
'서버에 메시지가 저장되는데 어떻게 못 읽지?'가 가장 흔한 혼동이다. 서버가 갖는 것은 E2E 암호문뿐이고 키는 기기에만 있으며, 그마저 전달이 확인되는 즉시 삭제된다. 두 번째 혼동은 체크 표시다 — 회색 1개는 '상대에게 감'이 아니라 '서버 도달'일 뿐이고, 상대 기기에 닿아야 회색 2개(delivered), 읽어야 파란 2개(read)다. 읽음 확인을 꺼둔 상대라면 읽어도 파란색으로 바뀌지 않는다.
애니메이션이 보여주는 것
첫 국면은 세션 수립이다. B가 오프라인이어도 미리 서버에 올려둔 Pre Key(Identity·Signed Pre·One-Time Pre Key) 묶음만으로 A가 X3DH 공유 비밀을 만들 수 있다 — 전화처럼 '둘 다 접속 중'일 필요가 없는 비동기 키 합의가 메신저 E2E의 출발점이다. 이후 Double Ratchet이 돌며 메시지마다 새 Message Key를 파생한다. 키 하나가 새어도 과거 메시지를 열 수 없는 전방 비밀성이 여기서 나온다.
그 다음이 전달 경로다. 발신 폰이 수신자의 기기 수만큼 따로 암호화하는 client-fanout, 서버의 기기별 큐(store-and-forward)와 전달 즉시 삭제, 그리고 체크 표시의 세 단계. 오프라인 국면에서는 회색 1개에서 멈춘 메시지들이 상대 재접속과 함께 일괄 push·복호화·영수증 발송되어 체크가 한꺼번에 갱신되는 익숙한 장면의 내부를 보여준다.
폰과 노트북이 둘 다 받는 방법 — 기기가 단위다
WhatsApp 멀티디바이스의 단위는 계정이 아니라 기기다. 기기마다 자체 Identity Key와 자체 메시지 큐가 있고, 발신자는 상대 계정의 기기 목록을 받아 기기마다 pairwise 세션으로 따로 암호화한다(client-fanout). 폰의 키를 노트북에 복사하는 방식이 아니라서, 어느 기기가 뚫려도 다른 기기의 세션은 무사하다.
새 기기를 연결하면 그 기기가 자체 키를 만들어 기기 목록에 추가되고, 기존 폰이 대화 기록을 히스토리 번들로 암호화해 넘겨준다 — 기록 이전조차 서버가 열 수 없는 기기 간 E2E다. 대화 상대와 비교하는 보안 코드는 전체 기기 identity의 조합이라, 기기를 하나 추가할 때마다가 아니라 계정을 재등록할 때만 다시 비교하면 된다.
- 기기별 Identity Key — 계정이 아니라 기기가 암호화 단위
- 기기별 큐 — 각 기기가 자기 속도로 받아가고, 받는 즉시 서버에서 삭제
- 회색 1개에서 오래 멈춤 = 상대 기기가 서버에서 메시지를 못 받아가는 상태
그룹 30명인데 30번 암호화하지 않는 이유 — Sender Keys
1:1의 pairwise 세션을 그룹에 그대로 쓰면 구성원 수만큼 암호화해야 한다. 그래서 그룹은 Sender Keys를 쓴다 — 발신자가 자신의 Sender Key를 각 구성원에게 pairwise 세션으로 1회 배포해 두면, 이후 그룹 메시지는 한 번만 암호화하고 서버가 구성원별 큐에 사본을 놓는다. 암호화 비용이 수신자 수와 무관해진다.
그룹의 체크 표시는 '가장 늦은 구성원' 기준이다. 전원에게 전달되어야 회색 2개, 전원이 읽어야 파란 2개가 된다.
기억할 것
- X3DH + Pre Key = 상대가 오프라인이어도 세션을 시작할 수 있는 비동기 키 합의.
- Double Ratchet은 메시지마다 새 Message Key를 파생한다 — 키 유출이 과거로 번지지 않는 전방 비밀성.
- 팬아웃은 서버가 아니라 발신 클라이언트가 한다 — 수신 기기마다 개별 암호화(client-fanout).
- 서버는 암호문을 기기별 큐에 잠깐 맡을 뿐(store-and-forward), 전달 확인 즉시 삭제한다.
- 체크 표시: 회색 1개=서버 도달(sent), 회색 2개=기기 전달(delivered), 파란 2개=읽음(read, 읽음 확인 꺼두면 안 바뀜).