1P by GN⁺ 20시간전 | ★ favorite | 댓글 1개
  • Mullvad는 서버 하나에 여러 exit IP를 두지만, WireGuard 키 기반으로 결정적으로 배정해 접속마다 무작위로 바뀌지 않음
  • 9개 서버에서 pubkey를 반복 변경해 모은 3,650개 데이터 포인트는 가능한 8.2조 개 조합 중 284개 조합에만 배정됨
  • 각 서버의 exit IP는 풀 안에서 비슷한 백분위 위치에 놓이며, 한 조합은 여러 서버에서 대체로 81번째 백분위에 맞춰짐
  • 원인은 pubkey나 터널 주소를 seed로 쓰고 풀 크기를 상한으로 넣는 seed 기반 RNG로 exit IP index를 고르는 구조로 보임
  • IP 로그의 float 범위가 겹치면 서로 다른 Mullvad 서버를 써도 계정 간 상관관계가 가능해져 익명성 위험이 커짐

Mullvad exit IP가 식별 벡터가 되는 구조

  • Mullvad는 서버 하나에 여러 exit IP를 제공하며, 같은 서버에 연결한 두 사용자가 보통 서로 다른 공개 IP를 받음
  • 서버 수는 578대로, Proton VPN의 20,000대보다 적어 한 IP에 사용자를 몰아넣지 않는 수직 확장이 과도한 IP 차단·속도 제한을 피하는 데 유리함
  • 하지만 서버에 연결할 때마다 exit IP가 무작위로 바뀌지 않고, WireGuard 키를 기반으로 결정적으로 선택
  • WireGuard 키는 1~30일마다 회전하지만, 서드파티 클라이언트에서는 회전하지 않음
  • 서버마다 독립적으로 고정 exit IP가 배정된다면, 몇 개 서버의 IP 조합만으로 다른 Mullvad 사용자와 구분될 수 있음

9개 서버에서 관찰한 exit IP 조합

  • pubkey를 반복 변경하며 9개 서버의 exit IP를 수집하는 스크립트를 밤새 실행해 3,650개 pubkey 데이터 포인트를 얻음
  • 각 서버의 exit IP 범위는 다음처럼 관찰됨
Hostname Start IP End IP # IPs
au-syd-wg-101 103.136.147.5 103.136.147.64 60
cl-scl-wg-001 149.88.104.4 149.88.104.14 11
de-ber-wg-007 193.32.248.245 193.32.248.252 8
dk-cph-wg-002 45.129.56.196 45.129.56.226 31
fi-hel-wg-201 185.65.133.10 185.65.133.75 66
us-lax-wg-001 23.234.72.36 23.234.72.126 91
us-nyc-wg-602 146.70.168.132 146.70.168.190 59
us-sjc-wg-302 142.147.89.212 142.147.89.224 13
za-jnb-wg-002 154.47.30.145 154.47.30.155 11
  • 이 서버들의 풀 크기를 곱하면 8.2조 개 이상의 exit IP 조합이 가능해 보임
  • 실제 테스트된 모든 pubkey는 그중 284개 조합 중 하나에만 배정됨
  • 가능한 조합 수에 비해 관찰된 조합 수가 매우 적어, 서버별 IP 선택이 독립적이지 않다는 단서가 됨

서로 다른 IP가 같은 백분위에 놓이는 패턴

  • exit IP는 풀 시작 IP에서 얼마나 떨어져 있는지로 숫자 위치를 계산할 수 있음
  • 예를 들어 au-syd-wg-101에서 103.136.147.53103.136.147.5부터 세면 1-based index가 49임
  • 관찰된 조합의 IP 위치를 각 서버의 풀 크기로 나누면, 서로 다른 서버에서도 거의 같은 비율이 나타남
Server IP Position Pool size Ratio
au-syd-wg-101 103.136.147.53 49 60 0.816
cl-scl-wg-001 149.88.104.12 9 11 0.818
de-ber-wg-007 193.32.248.251 7 8 0.875
dk-cph-wg-002 45.129.56.220 25 31 0.806
fi-hel-wg-201 185.65.133.63 54 66 0.818
us-lax-wg-001 23.234.72.109 74 91 0.813
us-nyc-wg-602 146.70.168.179 48 59 0.813
us-sjc-wg-302 142.147.89.222 11 13 0.846
za-jnb-wg-002 154.47.30.153 9 11 0.818
  • 각 IP는 해당 풀의 비슷한 백분위에 놓이며, 위 예시는 대체로 81번째 백분위에 해당함
  • 이 패턴 때문에 Mullvad는 모든 서버에서 서로 이웃한 위치의 exit IP만 배정하는 것처럼 보임

seed 기반 난수 선택으로 보이는 원인

  • cl-scl-wg-001za-jnb-wg-002는 관찰된 284개 IP 조합 전체에서 항상 같은 IP index를 공유함
  • 두 서버의 공통점은 풀 크기 11이며, 동일한 seed와 동일한 bounds를 가진 난수 호출이 같은 결과를 내는 구조와 맞음
  • 정적 seed로 RNG를 초기화한 뒤 같은 범위에서 난수를 뽑으면 같은 결과가 반복됨
  • Mullvad는 pubkey 또는 터널 주소를 seed로 쓰고, 풀 크기를 상한값으로 넣는 seed 기반 RNG로 exit IP index를 고르는 것으로 보임
  • bounds가 바뀌어도 RNG의 엔트로피 풀은 영향을 받지 않으며, Rust에서는 첫 호출에서 같은 float가 생성되어 bounds에 곱해지는 방식과 맞아떨어짐
  • 이 동작은 min + round((max - min) * float)처럼 단순화해 볼 수 있지만, 크게 단순화한 표현일 수 있음
  • 이런 특성 때문에 풀 크기가 달라도 같은 seed에서 나온 float가 각 서버 풀의 비슷한 비율 지점으로 매핑됨
  • Mullvad 클라이언트가 Rust로 작성되어 있어 Rust가 백엔드 언어일 가능성도 있지만, 이는 클라이언트 구현에 근거한 판단에 그침
  • random_range가 bounds 변화에 따라 어떻게 동작하는지 정확히 예상하기 어렵고, bounds 증가가 엔트로피와 섞여 다른 수를 만들 것이라고 생각하기 쉽지만 실제 관찰과는 다름

IP 로그 상관관계로 생기는 익명성 위험

  • 특정 IP 조합에서 가능한 float 값의 최솟값과 최댓값을 추정하는 도구가 mullvad-seed-estimator로 제공됨
  • 스크린샷의 특정 IP 집합은 0.2909~0.2943 사이의 float 값으로 해석되며, 차이는 0.0034임
  • 이는 Mullvad 사용자 중 0.34% 가 이 IP들을 공유한다는 뜻이고, 활성 사용자 100,000명이라는 대략적 추정에서는 340명에 해당함
  • 처음 예상한 수준만큼 고유하지는 않지만, 99% 이상 정확도는 낮지 않음
  • 예를 들어 포럼 관리자가 전날 차단한 사용자의 sockpuppet으로 의심되는 새 계정을 확인할 때, 두 계정이 서로 다른 Mullvad 서버를 써도 IP 로그가 0.4334 - 0.44280.4358 - 0.4423처럼 겹치는 float 범위에 있으면 같은 사람일 확률이 99%를 넘음
  • 데이터 유출이나 법적 절차로 확보한 IP 로그에도 같은 방식의 상관관계를 적용하면, VPN 뒤의 사용자가 익명성을 잃을 수 있음

보호 방법

  • pubkey 하나당 서버를 한 번 이상 바꾸지 않는 것이 권장됨
  • Mullvad 앱에서 로그아웃해 pubkey를 강제 회전할 수 있음

댓글과 토론

Hacker News 의견들
  • Mullvad에서 일하는 공동 CEO이자 공동 창업자임. 글에 나온 동작 중 일부는 의도한 것이고 일부는 아니며, 원인은 블로그 글 설명과 정확히 같지는 않음
    완화책으로는 의도하지 않은 동작에 대한 패치를 이미 인프라 일부에서 테스트 중이라, 오늘 재현을 시도하면 결과가 헷갈릴 수 있음
    의도된 동작도 받아들일 만한지 다시 평가할 예정이며, 여기에는 여러 프라이버시 요소와 사용자 경험 사이의 절충이 있음
    이 이해는 한 시간 전에 알게 된 뒤 운영팀과 즉시 대응을 논의하고 이 글을 쓰며 정리한 현재 판단이라 바뀔 수 있음
    보안 연구를 하는 분들은 보안·프라이버시 문제를 찾았을 때 바로 공개할 계획이더라도 먼저 관리자나 벤더에게 알려주길 바람

    • Mullvad 클라이언트는 기본적으로 키 교체 주기가 아마 72시간이고, CLI 클라이언트도 약간 손보면 네이티브 WireGuard를 쓰는 대부분의 상황에서 돌릴 수 있음
      mullvad tunnel get으로 확인하고 mullvad tunnel set rotation-interval 로 바꿀 수 있으며, 글에서 선호한 완화 방법도 이것임
      개인적으로는 반고정 IP가 크게 문제되지 않음. ISP와 정부의 네트워크 수준 감시를 막는 것이 목적이고, 일부 업체는 고정 IPv4를 기능으로 팔기도 함
      프라이버시 VPN에서는 IP 공간이 작을수록 외부에서 보이는 한 IP 뒤에 더 많은 사용자가 섞일 수 있어 장점도 있음. DAITA처럼 터널에 더미 트래픽을 넣는 기술과 멀티홉 진입점을 합치면, 하루 종일 넷플로를 들여다보는 감시자에게 실제로 더 어렵게 만들 수 있다고 봄
    • Obscura CEO이자 Mullvad 파트너 중 하나인 Carl임. 흥미로운 발견이지만, kfreds가 말했듯 공개 전에 벤더에게 알렸다면 더 좋았을 것임
      핵심 발견인 서버 간 IP 풀 내 위치 상관관계는 실제로 의도하지 않은 동작을 포함하는 것으로 보임. Mullvad 팀과 함께 일해본 경험상 곧 처리될 것이라 봄
      서로 다른 “신원”을 원한다면 WireGuard 키를 교체하거나 서로 다른 키를 써야 함
      기사에서 “서버에 연결할 때마다 출구 IP가 무작위가 아니라 WireGuard 키를 기준으로 결정적으로 선택되고, 그 키는 1~30일마다 교체된다. 서드파티 클라이언트를 쓰면 교체되지 않는다”라고 했는데, WireGuard는 설계상https://www.wireguard.com/protocol/ 연결 없는 프로토콜이라 연결 개념이 없고, 트래픽이 흐를 때만 2~3분마다 재키잉 핸드셰이크가 있을 뿐임
      같은 WireGuard 키에서도 “연결”할 때마다, 예컨대 재키잉 핸드셰이크마다 또는 15분마다 출구 IP가 바뀐다면 전송 계층에서는 QUIC을 제외한 거의 모든 터널 내부 연결이 끊겨 재수립되어야 하고, 애플리케이션 계층에서는 “같은 쿠키, 새 IP”를 의심하는 서비스들이 로그아웃, CAPTCHA, 위험 점수를 유발할 것임
      둘 다 사용자 경험이 나쁘고, 더 나쁘게는 “이 사람은 계속 다른 IP에서 재접속하니 Mullvad 사용자임”처럼 사용자를 더 독특하게 지문화할 수 있음
  • “포럼 운영자가 전날 차단한 사용자의 부계정인지 의심하고 IP 로그를 봤더니, 서로 다른 Mullvad 서버를 썼는데도 두 계정이 겹치는 부동소수 범위 0.4334~0.4428과 0.4358~0.4423에 매핑되어 99% 넘는 확률로 같은 사람이라고 볼 수 있다”는 예시는, 정보기관이 VPN을 설계한다면 이렇게 만들 것 같다는 느낌을 줌

    • 왜 그런지 모르겠음. 정보기관이 VPN을 설계한다면 출구 노드 통계에 의존하지 않고, 그냥 VPN에 접속하는 모든 IP를 로그로 남길 것임
      게다가 이 방식은 사용자가 서로 다른 서버를 고르는 것에 의존하니 더더욱 그럴 이유가 없음
    • 언젠가 Cloudflare도 정보기관과 연관됐다는 사실이 드러날 것 같음. “갑작스러운 DDoS”의 해결책이 웹사이트를 Cloudflare 뒤에 두는 것이라면, 그런 갑작스러운 공격을 누가 할 수 있는지도 궁금해짐
    • 그래도 로그를 저장하지 않는다는 작은 디테일은 남아 있음
      내 기준으로는 큰 문제이고, 여러 VPN 출구 노드 사이의 상관분석을 가능하게 하지만 그게 전부임. 자동으로 사용자를 식별할 수 있게 하지는 않음
      다만 식별 난이도는 크게 낮추며, 요구 조건은 여전히 높음. 곧 고치길 바람
      “해시 같은 민감한 값으로 만들자”식 실수가 아직도, 그것도 Mullvad에서 일어난다는 게 믿기지 않음. 그냥 무작위화하면 안 됐나 싶음
    • Mullvad는 Snowden 폭로보다 몇 년 앞서 존재했고, 그 자료 어디에도 나오지 않았음
      물론 다른 정보기관도 있지만 가장 걱정할 곳은 그쪽임. 직접 운영하거나, 그런 아이디어를 알고 따라 하거나, 파트너 기관이 운영하는 서비스에 접근권을 가졌을 테니까임. 아니면 나에게 위협이 아니겠고
      또 Mullvad 사용자가 VPN을 통해 비익명화된 공개 사례가 없고, 대신 다른 작전 보안 실패로 발견된 경우만 알려져 있음. 정보기관이 이 능력을 갖고 있었다면 거의 20년 동안 데이터를 갖고도 쓰지 않았다는 뜻이라 믿기 어려움
    • 정보기관이 VPN을 통제한다면 그냥 트래픽을 직접 감시하면 됨. 외부 관찰자가 어떤 사용자가 어떤 출구 IP로 나오는지 추측하기 쉽게 만들 유인은 없음
  • 글의 숫자만으로 “99% 넘는 확률”이 어떻게 나오는지 모르겠음. 첫 번째 차단 IP의 시드와 두 번째 시드가 모두 0.4423~0.4358 범위에 있다고 강하게 가정해도, 이 범위는 전체 Mullvad 사용자 중 0.65%를 포함한다는 뜻일 뿐임
    사용자 10만 명이면 650명이고, “용의자”를 99% 넘게 제거한 것이지 여러 출구 IP에 걸쳐 한 개인을 99% 넘는 정확도로 식별한 것은 아님
    베이즈식으로 보면 잠재 시드의 겹침은 두 IP가 같은 사람, 적어도 같은 Mullvad 계정이라는 강한 증거가 되지만, 글쓴이가 말한 내용은 그게 아닌 것처럼 보임

    • 포럼이 큰 편이라 활성 사용자 1000명이고 매일 1명 가입한다고 해보면, 누군가 차단된 다음 날 이 VPN을 쓰는 사람이 가입하고 비슷한 범위의 IP를 가질 확률이 얼마나 될까 싶음
      대부분의 작은 웹사이트에서는 꽤 강한 증거가 됨
  • VPN의 목적에는 방문 사이트에 대해 사용자를 익명화하는 것이 포함되지 않으므로, Mullvad가 고유한 출구 IP를 강제하지 않는다고 해서 놀랄 일은 아님. 익명성을 원하는 사용자는 Tor 같은 네트워크를 써야 함

    • 왜 안 되는지 모르겠음. 특정 VPN 서비스의 목적이 그렇게 될 수 없는 이유가 없음
    • Tor는 미국 정부 프로젝트이고 비익명화 가능하다는 것이 보여진 적 있지 않나?
    • 그게 바로 공개 VPN의 목적임
      공개 VPN을 쓴다면 요청을 누가 보내는지, 종단 IP를 포함해 아무도 몰랐으면 함
      그 논리라면 VPN은 토렌트에 쓰면 안 됨. 종단 IP에 대해 익명화해주면 안 된다는 뜻이기 때문임. 하지만 실제로는 토렌트에서 아주 잘 작동함
      사설 VPN을 말하는 거라면 Mullvad는 그런 게 아님
  • 오랫동안 Mullvad를 써왔고, 내 나라에서 합법인 한 내 이름이 적힌 신용카드로 Mullvad VPN 서비스를 계속 구매하고 사용할 것임
    VPN은 100% 익명이 아니고, 그렇게 설계된 것도 아님. 대신 법을 지키는 성인에게 어느 정도 프라이버시를 제공하기 위한 것임
    대부분의 사람은 동료와 이웃이 자신의 사적인 삶, 좋아하는 것, 사는 것, 하는 일을 알게 되면 민망할 것임. 그래서 대부분은 프라이버시 보호를 위해 VPN을 써야 함
    정의상 “대부분의 사람”은 온라인에서 100% 익명성을 원하거나 기대하지 않고, 개인 생활과 관계에서 약간의 프라이버시를 원할 뿐임
    VPN은 온라인 범죄를 저지르며 정부로부터 100% 익명성을 원하는 범죄자를 보호하지 않고, 그럴 의도도 없음. 이 구분은 중요함. “대부분의 사람”은 범죄자가 아니며 Mullvad나 다른 VPN 제공자에게 그런 비현실적 기대를 하지 않음

    • VPN이 익명은 아니고, 사람들이 그런 척할 뿐임. 그래도 이 보고서의 발견은 예상보다 사용자 식별을 쉽게 만드는 요소를 보여줌
      위 논리만으로 보고서를 버릴 수는 없음. 발견 자체는 여전히 타당함
  • 빠진 내용이 있음. Mullvad에 연락했는지 궁금함. 보안팀이 어떻게 대응했는지도 봤다면 흥미로웠을 것임

    • 내가 아는 한 연락은 없었고, 운영팀과 지원팀 모두에 확인했음. 내가 틀렸다면 이 글을 업데이트하겠음
      나중에 보니 이 댓글을 단 것이 후회됨. 불필요했지만 지금 지우면 이상해 보일 것 같음
    • 아니지만, 이 게시물의 최상위 추천 댓글이 Mullvad 공동창업자의 답변임
  • 사람들이 VPN을 Tor와 비슷할 것으로 기대한다는 게 놀랍게 느껴짐
    그렇게 풀어 쓰면 말이 안 되는 것처럼 보이고, 출구 노드를 통제하면 Tor 사용자조차 비익명화가 가능하다는 점도 생각해야 함

    • 대형 소비자용 VPN 대부분이 마케팅에서 “프라이버시”를 익명성처럼 암시하니, 놀랄 일은 아님
    • Tor 설계의 일부가 여러 릴레이 노드를 거치는 것이어서, 출구 노드도 원본 IP를 보지 못하는 것 아니었나?
    • 기대되는 건 아닐 수 있지만, 가능하다면 프라이버시를 제공하기 위해 할 수 있는 일을 하려 할 것이라고 생각하게 됨
  • “출구 IP가 연결할 때마다 무작위화되지 않고 WireGuard 키를 기준으로 결정적으로 선택되며, 이 키는 1~30일마다 교체된다. 서드파티 클라이언트를 쓰면 절대 교체되지 않는다”는 부분이 조금 헷갈림
    저장소에 방법이 자세히 나와 있다면, 서드파티가 기본 앱 클라이언트처럼 키 교체를 하지 못하게 막는 게 무엇인지 모르겠음

    • 서드파티 클라이언트에는 예를 들어 Linux 커널의 WireGuard 드라이버도 포함됨. 네트워크 드라이버가 특정 상용 서비스 하나에 대한 공격을 완화하는 일을 맡을 수는 없음
    • 주로, 그렇게 해야 한다는 사실을 아는 것이 막고 있음
  • 글쓴이가 잘 찾아냈고, Mullvad의 실수였다는 것도 충분히 믿을 수 있음. 이렇게 단순한 것이 지나갔다는 건 꽤 충격적이지만 나도 놓칠 수 있었을 것 같음
    여러 서버 간 IP 상관관계를 빼고 보면, 처음에는 왜 한 서버에서 사용자 IP를 안정적으로 유지하는지도 궁금했음. 하지만 다른 VPN은 보통 서버당 IP가 하나라서 그것을 흉내 내는 셈이라는 글쓴이 설명을 보면 말이 됨
    사용자가 어떤 서비스에 접근 가능한 서버를 찾으면, 다시 그 서버에 연결했을 때 같은 IP를 받아 다시 동작할 가능성이 있다는 장점이 있음
    다만 여러 서버 간 IP 상관관계는 rand.seed(user_pub_key + server_id) 같은 방식으로 고쳐야 함

    • 반대로 같은 IP의 시끄러운 이웃 때문에 어떤 서비스에서 차단당했다면, 사용자가 우회할 방법이 없는 것 아닌가?
  • IPinfo에서 일하고 있음. 우리는 VPN 탐지 사업을 하지만, 솔직히 Mullvad에는 선의로 해석하고 싶음
    우리 같은 IP 지리위치 제공자에게 부정확한 지리위치 정보를 제출하려 하지 않았던 VPN 제공자 셋 중 하나가 Mullvad였음. 이 문제도 고칠 것이라 확신함

    • 나머지는 어디였음?