위협 모델 & OWASP ASVS L1 자가 증명

Vaulted가 방어하도록 설계된 위협, 방어하지 않는 위협, 그리고 업계 기준선에 대한 항목별 증명.

버전 1.0 · 게시일 2026-04-27 · 소스: main · 작성자: Maxim Novak

이 문서에 대하여

이것은 자가 증명이며, 서드파티 감사가 아닙니다. Vaulted가 보호한다고 주장하는 것, 그렇지 않은 것, 각 설계 결정이 인정된 통제와 어떻게 연결되는지 정확히 볼 수 있도록 존재합니다. 예산이 허락하면 독립적인 검토를 의뢰하고 결과 보고서를 이 페이지와 함께 게시할 것입니다. 그전까지는 핵심 제로 지식 주장을 직접 검증할 수 있습니다 — 브라우저 DevTools로 5분이면 됩니다.

1. 범위 & 가정

이 모델은 vaulted.fyi의 프로덕션 배포를 대상으로 하며, 웹 프런트엔드, API 라우트, Upstash Redis 스토리지를 포함합니다. 또한 동일한 API와 상호작용하는 범위 내에서 게시된 CLI 및 MCP 서버도 포함합니다.

범위 외:

  • 사용자의 엔드포인트 기기(브라우저, OS, 확장 프로그램, 클립보드, 화면).
  • 공유 링크가 전달되는 통신 채널(이메일, Slack, SMS 등).
  • 수신자가 플레인텍스트를 이후에 처리하는 방식.
  • 당사가 사용하는 API 표면 아래 Vercel 또는 Upstash의 취약점.

2. 자산 & 신뢰 경계

기본 자산: 플레인텍스트 시크릿. 서버에 절대 도달해서는 안 되며, 발신자와 수신자의 브라우저 외부에서 지속되어서는 안 되고, 서버 측 상태만으로는 복구할 수 없어야 합니다.

보조 자산: 사이퍼텍스트, IV, 조회 카운터, 만료 타임스탬프, 그리고 서비스의 무결성과 가용성.

신뢰 경계(신뢰도 내림차순):

  1. 발신자 브라우저 — 플레인텍스트와 키를 신뢰합니다.
  2. 수신자 브라우저 — 링크를 입력한 후 플레인텍스트와 키를 신뢰합니다.
  3. 클라이언트와 서버 사이의 네트워크 — 신뢰할 수 없음; TLS 1.3과 사이퍼텍스트만 통과한다는 설계 결정으로 완화됩니다.
  4. Vaulted 서버(당사) — 반신뢰. 수동적 사이퍼텍스트 저장소로 취급됩니다. 위협 모델은 Vaulted 자체가 침해되더라도 플레인텍스트가 노출되지 않는다고 가정합니다.
  5. Upstash Redis — 서버와 동일한 신뢰 수준. 암호화된 블롭만 저장.

3. 위협 행위자

수동적 네트워크 관찰자. ISP, TLS 메타데이터에 접근할 수 있는 경로상 행위자. TLS와 네트워크에 플레인텍스트나 키가 없다는 설계로 방어됩니다.

능동적 네트워크 공격자. MitM을 시도할 수 있습니다. TLS, HSTS 프리로드, 인증서 검증으로 방어됩니다. TLS 침해가 성공해도 사이퍼텍스트만 얻습니다.

침해된 서버 / 적대적 운영자. 당사 포함. 키가 절대 도달하지 않으므로 저장된 시크릿을 읽을 수 없습니다. 서비스를 거부하거나 제공된 JS 번들을 수정할 수 있습니다 — 아래 잔여 위험에서 다룹니다.

유효한 공유 링크를 가진 비인증 공격자. 설계상, 전체 링크를 가진 누구나 복호화할 수 있습니다. 조회 제한, 만료, 선택적 패스프레이즈가 기회를 줄입니다. 이것은 의도된 특성이며 버그가 아닙니다.

특정 발신자 또는 수신자를 대상으로 하는 표적 공격자. 엔드포인트, 전달 채널 또는 수신자의 복호화 후 처리를 악용할 수 있습니다. Vaulted의 통제 범위 밖입니다; 투명성을 위해 문서화되었습니다.

4. 통제

  • crypto.getRandomValues에서 생성된 무작위 96비트 IV를 사용하는 클라이언트 측 AES-256-GCM.
  • 시크릿당 crypto.subtle.generateKey로 생성된 256비트 키; URL 프래그먼트에 배치되며 절대 전송되지 않습니다.
  • PBKDF2(높은 반복 횟수)와 AES-GCM 키 래핑을 사용하는 선택적 패스프레이즈 래핑.
  • Redis HINCRBY를 통한 원자적 조회 횟수 적용, 한도 도달 시 동일 트랜잭션에서 삭제.
  • 최대 30일로 제한된 TTL 기반 자동 만료; 생성 후 연장 불가.
  • 생성 및 조회 엔드포인트에서 IP별 슬라이딩 윈도우 속도 제한.
  • noindex — /s/[id] 조회 페이지에서 시크릿 URL이 검색을 통해 유출되지 않도록.
  • HSTS 프리로드를 갖춘 TLS 1.3, 보안 헤더, 속도 제한 윈도우 이상의 IP 로깅 없음.

5. 잔여 위험 (방어하지 않음)

이것은 의도적인 경계 결정으로, 사용자가 Vaulted가 자신의 위협 모델에 적합한지 결정할 수 있도록 문서화되었습니다.

  • 엔드포인트 침해. 키로거, 감염된 브라우저, 또는 적대적 확장 프로그램이 복호화 후 플레인텍스트를 읽을 수 있습니다.
  • 전달 채널 유출. 공유 링크가 전달되거나, 보관되거나, 답장 이메일 스레드에 인용되면 해당 채널이 공격 표면이 됩니다.
  • 표적 번들 교체. 침해된 CDN 또는 Vercel 엣지가 특정 사용자에게 다른 JS를 제공할 수 있습니다. 서브리소스 무결성과 재현 가능한 빌드가 부분적인 완화책이며 로드맵에 있습니다.
  • 수신자 행동. 복호화된 후 수신자는 복사, 스크린샷 또는 전달할 수 있습니다.
  • 약한 패스프레이즈. 사용된 경우, 약한 패스프레이즈는 래핑된 키를 가진 누구나 무차별 대입으로 크래킹할 수 있습니다.
  • 강압 / 물리적 협박. 어떤 기술적 통제의 범위 밖입니다.

6. OWASP ASVS L1 자가 증명

아래 매트릭스는 Vaulted의 구현을 선별된 OWASP ASVS Level 1 요구 사항에 매핑합니다. 적용되지 않는 카테고리(세션, 인증, 파일 업로드)는 생략하지 않고 간략한 근거와 함께 N/A로 표시되어 있습니다 — 항목 부재가 회피로 읽히지 않도록 하기 위해서입니다.

ID카테고리요구 사항상태증거
V1.1.1아키텍처애플리케이션에 대한 위협 모델링을 포함한 보안 SDLCPass이 문서. 모든 주요 아키텍처 변경 시 검토됩니다.
V1.4.1아키텍처신뢰할 수 있는 적용 지점에서 접근 통제 강제PassAPI 라우트 핸들러가 입력을 검증하고 src/lib/redis-secrets-store.ts의 Redis HINCRBY를 통해 원자적으로 조회를 소비합니다.
V2.10.x인증서비스 / 사용자 인증N/AVaulted는 익명입니다. 사용자 계정 없음, 서비스 간 인증 없음. 인가는 시크릿 ID와 URL 프래그먼트 키 지식으로 이루어집니다.
V3.x세션 관리세션 관리 요구 사항N/A세션 없음, 인증 상태를 위한 쿠키 없음.
V5.1.3입력 검증신뢰할 수 있는 서비스 레이어에서 입력 검증Passsrc/app/api/secrets/route.ts에서 수동 런타임 검증. 페이로드 ≤ 1000자 서버 측 강제; 최대 조회수 및 TTL 제한.
V5.2.5소독컨텍스트(HTML, JS, URL)에 맞는 출력 인코딩PassReact는 기본적으로 모든 보간된 값을 이스케이프합니다. 유일한 dangerouslySetInnerHTML 호출은 서버 측에서 타입된 데이터로 구성된 JSON-LD 리터럴을 렌더링합니다.
V6.2.1저장된 암호화안전한 기본값으로 승인된 암호화 알고리즘 사용PassWeb Crypto API를 통한 AES-256-GCM. NIST SP 800-38D. src/lib/crypto.ts 참조.
V6.2.2저장된 암호화암호학적으로 강력한 난수 생성PassIV와 키 재료에는 crypto.getRandomValues. AES 키에는 crypto.subtle.generateKey.
V6.2.5저장된 암호화안전하지 않거나 더 이상 사용되지 않는 암호화 기본 요소 없음Pass암호화 경로 어디에도 MD5, SHA-1, DES, RC4, ECB 또는 CBC-without-MAC 없음.
V6.3.1저장된 암호화무단 접근으로부터 키 보호Pass암호화 키가 서버에 절대 도달하지 않습니다. RFC 3986에 따라 클라이언트 측에서 처리되는 URL 프래그먼트에만 존재합니다. 선택적 패스프레이즈가 공유 전에 PBKDF2로 키를 래핑합니다.
V7.1.1오류 처리 & 로깅로그에 민감한 정보 없음Pass서버는 요청 형태와 속도 제한 결정만 로깅합니다. 사이퍼텍스트 없음, 교차 상관될 수 있는 방식의 시크릿 ID 없음, 속도 제한 윈도우 이상으로 지속되는 IP 없음.
V7.4.1오류 처리 & 로깅일반적인 오류 메시지PassAPI 라우트는 일반적인 HTTP 상태 코드와 짧은 오류 문자열을 반환합니다. 스택 추적이나 내부 상태가 유출되지 않습니다.
V8.1.1데이터 보호민감한 데이터 식별 및 보호Pass서버는 플레인텍스트를 절대 수신하지 않습니다. 사이퍼텍스트는 TTL 기반 삭제와 원자적 조회 제한 적용을 통해 Upstash Redis에 암호화하여 저장됩니다.
V8.3.1데이터 보호URL이나 리퍼러에 민감한 데이터 노출 없음Pass암호화 키는 URL 프래그먼트에 있습니다; 프래그먼트는 RFC 3986 §3.5에 따라 서버에 전송되지 않으며 브라우저에 의해 document.referrer에서 제거됩니다.
V9.1.1통신모든 클라이언트 연결에 TLSPassVercel 엣지에서 TLS 1.3 강제. HSTS 프리로드됨. HTTP 요청은 HTTPS로 리디렉션됩니다.
V10.3.2악성 코드악성 코드에 대한 애플리케이션 코드 검토Pass단일 유지 관리자 코드베이스. 모든 커밋은 프로젝트 소유자가 작성; 지원되는 경우 서명된 커밋. 병합 전 Dependabot을 통해 검토된 의존성 업데이트.
V11.1.1비즈니스 로직남용으로부터 보호된 로직 흐름PassUpstash Ratelimit을 통한 IP별 속도 제한(10회 생성/분, 30회 조회/분). 조회 카운터 원자적 감소.
V12.x파일 & 리소스파일 업로드 및 처리 요구 사항N/AVaulted는 파일 업로드를 허용하지 않습니다.
V13.2.1API & 웹 서비스RESTful 엔드포인트에서 요청 스키마 검증Pass모든 POST/GET 핸들러가 처리 전에 경로 매개변수, 본문 형태, content-type을 검증합니다.
V14.4.3설정표준 보안 헤더 설정PassNext.js 설정을 통해 HSTS, X-Content-Type-Options, Referrer-Policy, Permissions-Policy 설정. nonce 기반 strict-dynamic script-src를 사용하는 Content-Security-Policy가 src/proxy.ts에서 요청별로 강제됩니다; API 라우트는 잠긴 default-src none 정책을 받습니다.

번호 매기기는 ASVS 4.0 구조를 따릅니다. 목록은 선별된 것으로 완전하지 않습니다 — 상태 비저장 계정 없는 암호화된 사이퍼텍스트 저장소에 의미 있게 적용되는 통제에 대한 정직함이 목표입니다.

7. 변경 프로세스

이 문서의 항목에 영향을 미치는 모든 변경 — 새 엔드포인트, 암호화 변경, 의존성에 영향을 미치는 리팩터링, 인프라 변경 — 은 동일한 PR에서 이 페이지 검토를 트리거해야 합니다. 문서가 업데이트될 때 위의 버전과 게시 날짜가 증가합니다; 이전 버전은 공개 git 기록에서 접근 가능합니다.

서명

이 위협 모델은 Vaulted 유지 관리자가 선의로 게시합니다. 오류, 누락, 위의 증명에 대한 이견은 명시적으로 환영합니다 — [email protected] 또는 책임 있는 공개 프로그램.

Maxim Novak — 유지 관리자, vaulted.fyi · 2026-04-27