위협 모델 & 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, 조회 카운터, 만료 타임스탬프, 그리고 서비스의 무결성과 가용성.
신뢰 경계(신뢰도 내림차순):
- 발신자 브라우저 — 플레인텍스트와 키를 신뢰합니다.
- 수신자 브라우저 — 링크를 입력한 후 플레인텍스트와 키를 신뢰합니다.
- 클라이언트와 서버 사이의 네트워크 — 신뢰할 수 없음; TLS 1.3과 사이퍼텍스트만 통과한다는 설계 결정으로 완화됩니다.
- Vaulted 서버(당사) — 반신뢰. 수동적 사이퍼텍스트 저장소로 취급됩니다. 위협 모델은 Vaulted 자체가 침해되더라도 플레인텍스트가 노출되지 않는다고 가정합니다.
- 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 | 아키텍처 | 애플리케이션에 대한 위협 모델링을 포함한 보안 SDLC | Pass | 이 문서. 모든 주요 아키텍처 변경 시 검토됩니다. |
| V1.4.1 | 아키텍처 | 신뢰할 수 있는 적용 지점에서 접근 통제 강제 | Pass | API 라우트 핸들러가 입력을 검증하고 src/lib/redis-secrets-store.ts의 Redis HINCRBY를 통해 원자적으로 조회를 소비합니다. |
| V2.10.x | 인증 | 서비스 / 사용자 인증 | N/A | Vaulted는 익명입니다. 사용자 계정 없음, 서비스 간 인증 없음. 인가는 시크릿 ID와 URL 프래그먼트 키 지식으로 이루어집니다. |
| V3.x | 세션 관리 | 세션 관리 요구 사항 | N/A | 세션 없음, 인증 상태를 위한 쿠키 없음. |
| V5.1.3 | 입력 검증 | 신뢰할 수 있는 서비스 레이어에서 입력 검증 | Pass | src/app/api/secrets/route.ts에서 수동 런타임 검증. 페이로드 ≤ 1000자 서버 측 강제; 최대 조회수 및 TTL 제한. |
| V5.2.5 | 소독 | 컨텍스트(HTML, JS, URL)에 맞는 출력 인코딩 | Pass | React는 기본적으로 모든 보간된 값을 이스케이프합니다. 유일한 dangerouslySetInnerHTML 호출은 서버 측에서 타입된 데이터로 구성된 JSON-LD 리터럴을 렌더링합니다. |
| V6.2.1 | 저장된 암호화 | 안전한 기본값으로 승인된 암호화 알고리즘 사용 | Pass | Web Crypto API를 통한 AES-256-GCM. NIST SP 800-38D. src/lib/crypto.ts 참조. |
| V6.2.2 | 저장된 암호화 | 암호학적으로 강력한 난수 생성 | Pass | IV와 키 재료에는 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 | 오류 처리 & 로깅 | 일반적인 오류 메시지 | Pass | API 라우트는 일반적인 HTTP 상태 코드와 짧은 오류 문자열을 반환합니다. 스택 추적이나 내부 상태가 유출되지 않습니다. |
| V8.1.1 | 데이터 보호 | 민감한 데이터 식별 및 보호 | Pass | 서버는 플레인텍스트를 절대 수신하지 않습니다. 사이퍼텍스트는 TTL 기반 삭제와 원자적 조회 제한 적용을 통해 Upstash Redis에 암호화하여 저장됩니다. |
| V8.3.1 | 데이터 보호 | URL이나 리퍼러에 민감한 데이터 노출 없음 | Pass | 암호화 키는 URL 프래그먼트에 있습니다; 프래그먼트는 RFC 3986 §3.5에 따라 서버에 전송되지 않으며 브라우저에 의해 document.referrer에서 제거됩니다. |
| V9.1.1 | 통신 | 모든 클라이언트 연결에 TLS | Pass | Vercel 엣지에서 TLS 1.3 강제. HSTS 프리로드됨. HTTP 요청은 HTTPS로 리디렉션됩니다. |
| V10.3.2 | 악성 코드 | 악성 코드에 대한 애플리케이션 코드 검토 | Pass | 단일 유지 관리자 코드베이스. 모든 커밋은 프로젝트 소유자가 작성; 지원되는 경우 서명된 커밋. 병합 전 Dependabot을 통해 검토된 의존성 업데이트. |
| V11.1.1 | 비즈니스 로직 | 남용으로부터 보호된 로직 흐름 | Pass | Upstash Ratelimit을 통한 IP별 속도 제한(10회 생성/분, 30회 조회/분). 조회 카운터 원자적 감소. |
| V12.x | 파일 & 리소스 | 파일 업로드 및 처리 요구 사항 | N/A | Vaulted는 파일 업로드를 허용하지 않습니다. |
| V13.2.1 | API & 웹 서비스 | RESTful 엔드포인트에서 요청 스키마 검증 | Pass | 모든 POST/GET 핸들러가 처리 전에 경로 매개변수, 본문 형태, content-type을 검증합니다. |
| V14.4.3 | 설정 | 표준 보안 헤더 설정 | Pass | Next.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