5분 감사

Vaulted의 zero-knowledge 암호화를 직접 검증해

보안 도구를 믿지 말고 직접 검증해. 브라우저 테스트 4개, 설치 없음, 5분.

60초 체크리스트

먼저 훑어봐. 아래 상세 안내에서 각 단계를 깊이 다뤄.

  1. 1

    DevTools 열기 → Network 탭

    Vaulted에서 Cmd+Option+I (macOS) 또는 F12 (Windows/Linux)를 눌러. Network 탭으로 전환하고 Fetch/XHR으로 필터링해.

  2. 2

    시크릿 만들고 POST 검사하기

    알아볼 수 있는 카나리 문자열(예: CANARY-12345)을 입력하고 Create를 클릭해. POST /api/secrets 요청을 찾아. Payload 탭을 열면 — 암호문(base64)과 iv만 보여. 본문에서 카나리를 검색해보면 없어.

  3. 3

    공유 링크 검사하기

    생성된 링크를 봐. 복호화 키는 # 뒤(URL 프래그먼트)에 있어. RFC 3986에 따라 브라우저는 프래그먼트를 서버에 절대 보내지 않아 — 요청 라인, 헤더, 리퍼러 어디에도 없어.

  4. 4

    복호화가 클라이언트 사이드에서 실행되는지 확인하기

    새 탭에서 링크를 열어. /api/secrets/[id]의 GET 응답은 암호문만 반환해. Sources 패널에서 crypto.subtle.decrypt를 검색하면 — 그 호출은 우리 서버가 아닌 네 브라우저에서 실행돼.

무엇을 검증하는 건지

Vaulted의 주장은 구체적이야: 서버는 평문도, 암호화 키도 절대 보지 않아. 이건 네 가지 관찰 가능한 속성으로 나눌 수 있어:

  1. 평문은 어떤 네트워크 요청에도 나타나지 않아.
  2. 암호화 키는 어떤 네트워크 요청에도 나타나지 않아.
  3. URL 프래그먼트(키가 있는 곳)는 서버에 절대 도달하지 않아.
  4. 서버 사이드 데이터만으로는 시크릿을 복원할 수 없어.

네 가지 모두 성립하면, 아키텍처는 구조적으로 zero-knowledge야 — 마케팅 언어가 필요 없어.

테스트 1평문은 네트워크를 절대 통과하지 않아

  1. vaulted.fyi를 열어.
  2. DevTools를 열고 Network 탭으로 전환해. Fetch/XHR으로 필터링해.
  3. 시크릿 필드에 알아볼 수 있는 문자열을 입력해 — 예를 들어 CANARY-12345 같은 거.
  4. Create를 클릭해.

단일 POST 요청이 /api/secrets으로 가는 걸 볼 수 있어. 클릭하고 Payload 탭을 봐.

본문에는 ciphertext 필드와 iv 필드가 있어. 둘 다 base64url 인코딩된 블롭이야. 페이로드에서 CANARY-12345를 검색해봐 — 없어. 평문은 요청이 전송되기 전에 브라우저에서 암호화됐어.

철저하게 확인하고 싶으면 네트워크 스로틀링을 "Slow 3G"로 설정하고 반복해봐. 암호문은 여전히 노이즈처럼 보이고, 평문은 여전히 어디에도 없어.

테스트 2키도 네트워크를 절대 통과하지 않아

시크릿을 만들면 Vaulted가 공유 링크를 보여줘. 이런 형태야:

https://vaulted.fyi/s/abc123#dGhpcyBpcyBhIGtleQ
                              ^^^^^^^^^^^^^^^^^^^^
                              encryption key (base64url)

# 뒤에 있는 부분이 URL 프래그먼트야. RFC 3986에 따라, 브라우저는 프래그먼트를 로컬에서 처리해 — HTTP 요청 라인, 헤더, 리퍼러 어디에도 나타나지 않아.

직접 증명해봐:

  1. 공유 링크를 복사해.
  2. DevTools의 Network 탭을 열고 새 탭에서 링크를 열어.
  3. GET /s/abc123 요청을 찾아.
  4. Headers 탭을 봐 — 전체 요청 URL, 프래그먼트 없음.
  5. Request 탭을 봐 — 프래그먼트 없음.
  6. 다음 페이지에서 document.referrer를 확인해 — 프래그먼트 제거됨.

수신자가 시크릿을 복호화하는 데 필요한 키는 URL에 있었지만, 그들의 브라우저 안에 머물렀어. 서버는 GET /s/abc123만 보고 그 이상은 없었어.

테스트 3서버 단독으로는 복호화할 수 없어

터미널을 열고 시크릿을 직접 curl로 가져와:

curl https://vaulted.fyi/api/secrets/abc123

ciphertextiv를 포함한 JSON을 받게 돼. 네 시크릿의 전체 서버 사이드 상태가 이게 다야.

이제 이걸 해석해봐. URL 프래그먼트의 키 없이는 불가능해. 제대로 생성된 랜덤 키로 만든 AES-256-GCM은 실용적인 관점에서 랜덤 노이즈와 구별할 수 없어. Vaulted 서버의 전체 데이터베이스 덤프를 가져와도 이것만 나와 — 암호화된 블롭과 메타데이터.

이게 zero-knowledge의 문자 그대로의 정의야: 서버는 읽을 수 없는 데이터를 저장해.

테스트 4암호화는 네가 볼 수 있는 JavaScript에서 일어나

Vaulted는 Web Crypto API를 사용해, 브라우저 내장 기능이야 — 작업을 숨기는 난독화된 WASM이나 네이티브 모듈이 없어. 암호화가 일어나는 걸 직접 볼 수 있어.

  1. DevTools에서 Sources 탭을 열어.
  2. crypto.subtle.encrypt를 검색해 (Cmd+Option+F로 전역 검색).
  3. crypto.subtle.encrypt를 호출하는 줄에 중단점을 설정해.
  4. 새 시크릿 생성을 트리거해.
  5. 중단점이 걸려. 인수를 검사해: 평문이 Uint8Array로, AES-GCM 키와 새 랜덤 IV를 볼 수 있어.
  6. 호출을 넘어가봐. 결과가 전송되는 암호문이야.

지금 네 브라우저에서, 어떤 네트워크 요청 전에, 평문이 암호문으로 변하는 걸 직접 보고 있어. 데이터가 다른 경로를 취할 수는 없어.

이게 증명하는 것

  • 평문은 브라우저 밖으로 나가지 않아. 테스트 1.
  • 키는 브라우저 밖으로 나가지 않아. 테스트 2.
  • 서버는 저장된 것만으로 복호화할 수 없어. 테스트 3.
  • 암호화는 실제이고 클라이언트 사이드에서 일어나. 테스트 4.

이게 전체 zero-knowledge 주장이야, 5분 안에 실제 프로덕션 시스템에서 직접 확인한 거야.

이게 증명하지 못하는 것

검증은 정직한 작업이야 — 한계를 명확히 하는 게 가치 있어.

  • 테스트는 지금 이 순간의 동작을 증명해. 향후 코드 변경이 이 속성을 깨뜨릴 수 있어. 지속적인 확신이 필요하면 변경 로그를 구독하고 주기적으로 테스트를 다시 실행해.
  • 네 기기를 보호하지는 않아. 키로거나 악성 브라우저 확장 프로그램은 복호화 후 평문을 읽을 수 있어. 이건 어떤 웹 앱의 통제 범위도 벗어나.
  • 네가 실행한 JavaScript가 Vaulted가 제공하는 JavaScript라고 가정해. CDN을 장악한 표적 공격자는 특정 사용자에게 다른 번들을 제공할 수 있어. Subresource Integrity와 재현 가능한 빌드가 이를 완화해. 전체 내용은 위협 모델을 참조해.

더 깊이 파고들기

더 자세히 알고 싶으면:

보안 도구에 대한 가장 강력한 논거는 마케팅이 아니야. 직접 분해해서 하는 일을 확인할 수 있다는 거야. Vaulted는 그렇게 할 수 있도록 만들어졌어.

자주 묻는 질문

질문이 있거나 이상한 점을 발견했어? [email protected]로 이메일 보내 — 책임 있는 공개 정책을 공개하고 있으며 48시간 내에 응답해.