우리는 사용자의 모든 비공개 Tor 신원을 연결하는 안정적인 Firefox 식별자를 발견했다

4 hours ago 2
  • indexedDB.databases()의 반환 순서만으로 Firefox 기반 브라우저에서 프로세스 수명 동안 유지되는 안정적 식별자 생성 가능
  • 이 식별자는 origin 범위를 넘어서 공유되어, 관련 없는 사이트들도 같은 브라우저 런타임 안에서 동일한 값을 관측하며 cross-origin 추적에 활용 가능
  • Firefox Private Browsing에서는 모든 프라이빗 창을 닫은 뒤에도 프로세스가 살아 있으면 식별자 유지되며, Tor Browser의 New Identity 이후에도 계속 남음
  • 원인은 Gecko의 IndexedDB 구현에서 프라이빗 데이터베이스 이름을 UUID 기반 파일명으로 매핑하고, 그 결과를 정렬 없이 노출하는 동작에 있음
  • Mozilla는 Firefox 150ESR 140.10.0에서 수정 배포했으며, 내부 저장소 순서를 외부에 드러내지 않는 설계가 프라이버시 보호에 중요함

취약점 개요

  • 모든 Firefox 기반 브라우저에서 indexedDB.databases()가 반환하는 항목 순서를 통해 프로세스 수명 동안 유지되는 식별자 추출 가능
    • 웹사이트가 여러 IndexedDB 데이터베이스를 만든 뒤 반환 순서를 확인하면, 실행 중인 브라우저 프로세스의 고유하고 결정적인 식별자 생성 가능
    • 이 동작은 origin 범위가 아니라 프로세스 범위에서 나타나며, 서로 관련 없는 사이트도 같은 브라우저 런타임 안에서 동일한 식별자 관측 가능
  • Firefox Private Browsing에서는 모든 프라이빗 창을 닫은 뒤에도 Firefox 프로세스가 계속 실행 중이면 식별자 유지
    • Tor Browser에서는 쿠키와 방문 기록을 지우고 새 Tor 회로를 사용하는 New Identity 이후에도 안정적 식별자 유지
    • 이후 브라우저 활동이 이전 활동과 연결되지 않아야 한다는 기대와 충돌하며, 사용자가 의존하는 비연결성 보장 약화
  • Mozilla와 Tor Project에 책임 있는 공개 진행
    • Mozilla는 Firefox 150ESR 140.10.0에서 수정 배포
    • 패치는 Mozilla Bug 2024220에서 추적 중이며, 원인은 Gecko의 IndexedDB 구현에 있어 Tor Browser와 다른 Firefox 기반 브라우저에도 연관됨
  • 수정 원리는 단순함
    • 브라우저가 프로세스 범위 내부 저장소 순서를 외부에 노출하지 않아야 함
    • 결과를 정규화하거나 정렬해 반환하면 엔트로피 제거와 안정적 식별자 악용 차단 가능

왜 중요한가

  • 프라이빗 브라우징 모드와 개인정보 보호 중심 브라우저는 서로 다른 맥락에서 사용자를 식별하기 어렵게 만드는 목적 보유
    • 일반적 기대 1: 공유 저장소나 명시적 신원 메커니즘이 없는 한, 관련 없는 사이트가 같은 브라우저 인스턴스와 상호작용 중인지 알 수 없어야 함
    • 일반적 기대 2: 프라이빗 세션이 끝나면 해당 세션과 연결된 정보도 함께 사라져야 함
  • 이번 동작은 두 기대를 모두 깨뜨림
    • 사이트는 쿠키, localStorage, 명시적 교차 사이트 채널 없이도 브라우저 내부 저장소 동작만으로 식별자 도출 가능
    • API가 반환하는 데이터베이스 이름 순서에서 고용량 식별 신호 획득 가능
  • 개발자 관점의 교훈 존재
    • 개인정보 취약점은 식별 데이터에 대한 직접 접근에서만 발생하지 않음
    • 내부 구현 세부 사항이 결정적으로 노출될 때도 개인정보 누출 가능
  • 보안 및 제품 관점의 핵심
    • 겉보기에는 무해한 API도 안정적인 프로세스 수준 상태를 누출하면 교차 사이트 추적 벡터로 전환 가능

IndexedDB와 indexedDB.databases()

  • IndexedDB는 클라이언트 측 구조화 데이터 저장용 브라우저 API
    • 웹 애플리케이션이 오프라인 지원, 캐싱, 세션 상태, 기타 로컬 저장 목적으로 활용
    • 각 origin은 하나 이상의 이름 있는 데이터베이스를 만들 수 있으며, object store와 대용량 데이터 저장 가능
  • indexedDB.databases()는 현재 origin에서 볼 수 있는 데이터베이스 메타데이터 반환
    • 개발자는 기존 데이터베이스 확인, 저장소 사용량 디버깅, 애플리케이션 상태 관리 등에 활용 가능
  • 정상적인 개인정보 보호 기대 아래에서는 이 API의 반환 순서 자체가 식별 정보를 담아서는 안 됨
    • 중립적이거나 정규화된 형태의 데이터베이스 메타데이터 표현 필요
    • 실제 문제는 Firefox 기반 브라우저에서 반환 순서가 전혀 중립적이지 않았다는 점

indexedDB.databases()가 안정적 식별자가 된 방식

  • Firefox Private Browsing에서 indexedDB.databases()는 데이터베이스 생성 순서가 아니라 내부 저장소 구조에서 파생된 순서로 메타데이터 반환
    • 관련 구현 위치는 dom/indexedDB/ActorsParent.cpp
  • Private Browsing에서는 데이터베이스 이름을 디스크 식별자로 직접 사용하지 않음
    • 대신 전역 해시 테이블 StorageDatabaseNameHashtable = nsTHashMap<nsString, nsString>를 통해 UUID 기반 파일명 베이스로 매핑
    • 이 매핑은 OpenDatabaseOp::DoDatabaseWork() 내부 GetDatabaseFilenameBase()에서 수행
  • aIsPrivate가 true일 때 사이트가 제공한 데이터베이스 이름은 생성된 UUID로 대체되어 전역 StorageDatabaseNameHashtable에 저장
    • 키는 데이터베이스 이름 문자열만 사용
    • IndexedDB QuotaClient 수명 동안 지속
    • 모든 origin 사이에서 공유
    • Firefox를 완전히 재시작할 때만 초기화
  • 이후 indexedDB.databases() 호출 시 Firefox는 GetDatabasesOp::DoDatabaseWork()에서 QuotaClient::GetDatabaseFilenames(...)를 통해 데이터베이스 파일명 수집
    • 데이터베이스 베이스 이름은 nsTHashSet에 삽입
    • 반복 전에 어떠한 정렬도 수행하지 않음
  • 최종 결과 순서는 해시 세트 내부 버킷 레이아웃 순회 결과로 결정
    • UUID 매핑이 Firefox 프로세스 수명 동안 안정적으로 유지되기 때문에, 반환 순서도 생성된 UUID 값, 해시 함수 동작, 해시 테이블 용량과 삽입 이력의 결정적 함수로 유지
    • 이 순서는 탭과 프라이빗 창을 가로질러 유지되며, 전체 Firefox 재시작 시에만 재설정
    • UUID 매핑과 해시 세트 순회 모두 origin 범위가 아니라 프로세스 범위

재현 방법

  • 단순한 PoC만으로 동작 입증 가능
    • 서로 다른 두 origin이 동일한 스크립트 호스팅
    • 각 스크립트는 고정된 이름 집합의 데이터베이스 생성, indexedDB.databases() 호출, 반환 순서 추출 및 출력 수행
  • 영향을 받는 Firefox Private Browsing과 Tor Browser 빌드에서 두 origin은 같은 브라우저 프로세스 수명 동안 동일한 순열 관측
    • 브라우저를 재시작하면 순열 변경
  • 개념적 출력 예시 제시
    • 생성 순서: a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p
    • 반환 순서: g,c,p,a,l,f,n,d,j,b,o,h,e,m,i,k
  • 핵심은 정확한 순서 자체가 아님
    • 원래 생성 순서와 다름
    • 관련 없는 origin들에서 같은 순서가 나타남
    • 새로고침, 새로운 프라이빗 창, 모든 프라이빗 창 종료 후에도 유지
    • 전체 브라우저 재시작에서만 새로운 순서 생성
    • 개인정보 보호 관점에서 원하지 않는 특성 직접 확인 가능

개인정보 영향

  • 이 취약점은 하나의 브라우저 런타임 안에서 cross-origin 추적과 same-origin 추적 모두 가능하게 함
  • cross-origin 영향

    • 관련 없는 웹사이트들이 같은 식별자를 독립적으로 도출해 동일한 실행 중 Firefox 또는 Tor Browser 프로세스와 상호작용 중임을 추론 가능
    • 쿠키나 다른 공유 저장소 없이도 도메인 간 활동 연결 가능
  • same-origin 영향

    • Firefox Private Browsing에서는 Firefox 프로세스가 계속 실행 중이면 모든 프라이빗 창 종료 후에도 식별자 유지
    • 사이트가 겉보기에는 새로운 프라이빗 세션처럼 보이는 이후 방문을 다시 인식 가능
    • Tor Browser에서는 안정적 식별자가 실행 중 브라우저 프로세스 안에서 New Identity 격리를 사실상 무력화
    • 완전히 분리되어야 하는 세션들 사이의 연결 허용
  • Tor Browser에서 특히 심각한 이유

    • Tor Browser는 교차 사이트 연결 가능성을 줄이고 브라우저 인스턴스 수준 식별을 최소화하도록 설계됨
    • 프로세스 수명 동안 유지되는 안정적 식별자는 이 설계 목표와 정면으로 충돌
    • 전체 프로세스 재시작 전까지만 살아남더라도 활발한 사용 중 비연결성 약화에 충분

엔트로피와 핑거프린팅 용량

  • 이 신호는 안정적일 뿐 아니라 용량도 높음
    • 사이트가 N개의 데이터베이스 이름을 제어하면 관측 가능한 순열 수는 N!
    • 이론적 엔트로피는 log2(N!)
  • 16개의 제어 가능한 이름이 있으면 이론적 공간은 약 44비트
    • 실제 환경의 동시 브라우저 인스턴스를 구분하기에 충분한 수준
  • 내부 해시 테이블 동작 때문에 실제 도달 가능한 순열 수는 다소 낮을 수 있음
    • 그러나 보안 측면의 핵심은 바뀌지 않음
    • 노출된 순서는 여전히 강한 식별자로 작동하기에 충분한 엔트로피 제공

수정 방법

  • 올바른 수정은 내부 저장소 레이아웃에서 파생된 엔트로피 노출 중단
    • 가장 깔끔한 완화책은 사전식 정렬 같은 정규 순서로 결과 반환
    • 개발자에게 API 유용성을 유지하면서 핑거프린팅 신호 제거 가능
  • 호출마다 출력을 무작위화하는 방식도 안정적 순서 은닉 가능
    • 다만 정렬이 더 단순하고 예측 가능하며, 개발자가 이해하기 쉬운 선택지
  • 보안 엔지니어링 관점의 이상적 수정 조건 명시
    • 개념적 복잡도 낮음
    • 호환성 위험 최소
    • 개인정보 누출 직접 제거

책임 있는 공개

  • Mozilla와 Tor Project에 책임 있는 공개 진행
    • Mozilla는 Firefox 150과 ESR 140.10.0에서 수정 배포
    • 패치는 Mozilla Bug 2024220에서 추적 중
  • 동작의 근원은 Gecko의 IndexedDB 구현
    • Tor Browser를 포함한 하위 Gecko 기반 브라우저도 자체 완화책이 없다면 영향권 포함

프라이버시 중심 설계

  • 작은 구현 세부 사항도 의미 있는 개인정보 문제로 이어질 수 있음
    • 관련 없는 웹사이트가 같은 브라우저 런타임 동안 origin을 넘어서 활동 연결 가능
    • 식별자가 사용자 기대보다 오래 살아남아 프라이빗 세션 경계 약화
  • 긍정적 요소는 수정이 단순하고 효과적이라는 점
    • 반환 전에 출력을 정규화하면 이 엔트로피 원천 제거 가능
    • 기대된 개인정보 경계 복원 가능
  • 놓치기 쉽지만 영향이 크고, 프라이버시 민감 기능을 만드는 과정에서 주의할 가치가 큰 유형의 취약점
Read Entire Article