qub 보안
시행일: 2026년 9월 23일 버전: 1.1 — 구현 정확성 검토
연구자를 위한 — 빠른 참조:
- 신고 발송처: 제목 접두어
[SECURITY]로 support@qub.social.- 포함할 내용: 취약점, 재현 단계, 개념 증명.
- 저희의 대응: 영업일 3일 이내에 수신 확인, 90일 이내에 수정 배포를 목표로 합니다.
- Safe Harbor: §12의 규칙을 따르는 선의의 연구(귀하의 것이 아닌 데이터에 접근하지 않음, 서비스 저하 없음, 문제를 입증하는 데 필요한 것을 넘어서는 데이터 보유 없음, 합리적인 공개 창 제공)에 대해 법적 조치를 취하지 않습니다.
자세한 내용은 §12(조율된 공개)에 있습니다.
저희에 대하여
qub.social은 VSPRY AUSTRALIA PTY LIMITED(ABN 41 631 026 330, Level 38, 71 Eagle Street, Brisbane QLD 4000, Australia)가 운영합니다. "qub", "저희", "당사"는 해당 법인을 의미합니다.
보안 문의처: 제목 접두어 [SECURITY]로 support@qub.social.
1. 저희의 접근 방식
qub은 신뢰 인프라입니다. 안전하지 않으면 제품은 무가치하므로, 보안은 기능이 아니라 — 기반입니다. 이 페이지는 저희 스택, 사용자의 데이터, 봉인된 콘텐츠의 무결성을 어떻게 보호하는지 구체적으로 설명합니다.
검증 가능한 시간적 약속의 가치는 인터넷의 더 많은 부분이 기계로 생성될수록 커집니다. 검증된 저장소 트랜잭션 또는 투명성 로그 앵커는 암호문이 늦어도 해당 블록 시각까지 존재했음을 입증할 수 있습니다. 봉인된 아티팩트는 이와 별개로 콘텐츠 무결성, drand 라운드 결속, 작성자 서명을 증명합니다. 이 주장들을 구분하는 것이 이 페이지가 지켜야 할 기준입니다.
저희는 귀하에게 저희를 신뢰하라고 요청하지 않습니다. 저희에게 요구되는 신뢰가 가능한 한 작도록 설계하며, 신뢰가 필요한 곳에서는 무엇이 신뢰되고 왜 그런지 정확히 설명합니다.
세 가지 원칙이 모든 설계 결정을 추동합니다:
- 서버가 볼 수 있는 것을 최소화합니다. 기본 브라우저 메시지 흐름에서는 평문과 래퍼 키가 사용자의 기기에 머뭅니다. 서버 측 Builder 봉인, 약정 공동서명, 명시적으로 활성화한 복구는 아래에 공개된 서로 다른 신뢰 경계를 갖습니다. 메타데이터를 보유하는 경우 선택한 기능에 필요한 범위로 제한합니다.
- 침해를 로컬에 국한합니다. 단일 구성 요소(저희 서버, 이메일 제공자, drand 노드)의 침해가 아직 공개 시간에 도달하지 않은 봉인된 평문을 노출해서는 안 됩니다.
- 프로토콜을 감사 가능하게 만듭니다. 봉인된 아티팩트는 공개 암호로 종단 간 검증 가능합니다. qub 아티팩트를 검증하기 위해 qub 서비스를 신뢰할 필요가 없습니다.
2. 위협 모델
2.1 보호 대상
- 공개 시간 전에 서버 측 저장 데이터에 대한 읽기 접근을 얻은 공격자. 기본 비공개 브라우저 흐름에서는 메타데이터와 불투명한 래핑 바이트를 얻지만 평문이나 K는 얻지 못합니다. 이 보호는 복구를 위해 명시적으로 보존된 K, drand 라운드 이후의 공개/래퍼 없는 전달, Builder
/api/v1/seal및 약정 흐름에 일시적으로 제공된 평문에는 적용되지 않습니다. - 브라우저와 저희 인프라 사이의 트래픽을 가로채는 공격자. TLS는 CDN 엣지에서 종료됩니다; 봉인된 페이로드는 전송 전에 이미 암호화되어 있습니다.
- 저장된 페이로드를 변조하는 공격자. 외부 래퍼 인증(있는 경우), 정규 디코딩, 본문 해시,
qub_id재도출, 라운드 결속, 선택적 서명으로 인해 변조 시 검증이 실패하며 열람기는 렌더링을 거부합니다. - 위조된 작성자 이메일을 서명 키에 묶으려는 공격자. 이메일 증명은 개인 서명 키의 소유와 이메일 받은편지함에 전달된 일회용 코드 모두를 필요로 합니다.
- 침해된 drand 비콘 운영자. drand 네트워크는 여러 독립 운영자에 걸쳐 임계값 BLS 서명을 사용합니다; 소수는 조기 공개 서명을 위조할 수 없습니다.
2.2 보호할 수 없는 것
저희는 한계에 대해 정직합니다. qub은 다음에 대해 방어할 수 없습니다:
- 봉인 전 사용자 기기의 침해. 로컬 키로거, 악성 브라우저 확장 또는 잠금 해제된 기기에 대한 물리적 접근은 작성 시점에 평문을 캡처할 수 있습니다.
- drand 임계값의 붕괴. 여러 독립 조직이 이를 어렵게 만들기 위해 특별히 drand 네트워크를 운영하지만, 암호학적으로 불가능하지는 않습니다: 충분한 운영자가 결탁하면, 시한 해제 키를 조기에 도출할 수 있습니다.
- 유효한 사본의 공개 속성. 공개/래퍼 없는 qub은 drand 라운드 이후 복호화할 수 있습니다. 비공개/래핑된 qub에는 K가 추가로 필요하며, 저장된 바이트와 K를 모두 획득한 사람은 라운드 이후 복호화할 수 있습니다. qub 제품 표면에서 제거하더라도 영구 저장소 및 앵커링된 로그 기록을 회수할 수는 없습니다.
- 기저 암호(AES-GCM, BLS12-381 페어링 가정, SHA3-256, ML-DSA-65)를 깨는 글로벌 공격자. 이러한 원시가 함락된다면, 암호 생태계 전반에 더 큰 문제가 있습니다.
3. 클라이언트 측 암호
기본 브라우저 메시지 흐름에서는 업로드 요청 전에 콘텐츠가 암호화됩니다. 두 가지 명시적 경로는 다릅니다. Builder /api/v1/seal은 메모리 내 봉인을 위해 의도적으로 평문과 호출자가 생성한 K를 Worker에 보내고, 약정 스테이징/공동서명은 양자 아티팩트를 완성할 수 있도록 서명된 구조화 약정을 서비스에 보냅니다. 어느 예외도 브라우저 경로의 종단 간 암호화로 오해해서는 안 됩니다.
3.1 시한 해제 암호
qub은 tlock을 사용합니다 — 미래의 drand 비콘 라운드에 키가 지정된 신원 기반 암호. 암호화는 drand 네트워크의 공개 키를 사용하여 브라우저에서 진행됩니다; 복호화 키는 대상 라운드에 도달했을 때만 drand 네트워크에 의해 공개적으로 공개됩니다. 누구도, 저희를 포함해, 시간보다 먼저 복호화 키를 재구성할 수 없습니다.
저희는 quicknet 체인을 대상으로 합니다:
- 3초 라운드 주기
- 비체인 모드(각 라운드는 독립)
- BLS12-381 G1 서명
- 체인 해시
52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971
quicknet 체인의 공개 키와 제네시스 시간은 클라이언트에 컴파일됩니다. 저희는 런타임에 체인 매개변수를 가져오지 않으므로, 악성 노드가 저희가 통제하는 체인을 대체할 수 없습니다.
3.2 대칭 암호
tlock 방식은 AES-256-GCM 콘텐츠 키를 래핑합니다. AES-GCM은 인증된 암호화를 제공합니다: 암호문에서 단일 비트가 뒤집히면 조용히 손상된 평문을 생성하는 대신 복호화가 실패합니다.
3.3 정규 직렬화
프로토콜 구조는 결정적 CBOR(RFC 8949 §4.2 핵심 결정적 인코딩)을 사용하여 직렬화됩니다. 동일한 논리 구조를 인코딩하는 두 구현은 동일한 CBOR을 생성합니다. 완성된 봉인 페이로드 자체는 결정적이지 않습니다. tlock과 외부 래퍼 암호화가 매번 새로운 무작위성을 사용하기 때문입니다. 본문 해시는 원시 본문 바이트에 대해 계산되며, 정규 인코딩은 주변의 서명/와이어 구조를 모호하지 않게 만듭니다.
저희는 일반 직렬화 라이브러리에 의존하기보다는 클라이언트와 서버 구현 모두에 대해 CBOR 인코더를 손으로 작성했습니다 — 요구 사항은 인체공학이 아니라 정확성이며, 속성 테스트가 두 구현 모두에서 실행되어 서로 일치함을 검증합니다.
회귀 테스트는 정규 와이어 형식이 프로토콜 원시 qub_id 필드 키를 넘어선 어떠한 qub 브랜드 바이트 시퀀스도 포함하지 않음을 주장합니다. 와이어 형식은 의도적으로 브랜드 중립적입니다 — 어떤 호환 가능한 열람기(저희 것이든 제3자의 것이든)도 어떤 배포가 봉인했든 상관없이 영구 저장소에서 어떤 qub이든 렌더링할 수 있습니다. 테스트는 미래 변경이 우연히 브랜드 참조를 일단 영구 저장소에 있으면 다시 쓸 수 없는 바이트에 굽는 것을 방지하는 트립와이어입니다.
3.4 본문 해싱 및 공개 전 무결성
모든 봉인된 페이로드는 원시 본문 바이트의 SHA3-256 해시를 운반합니다. 해시는 qub_id에 결속되며, 작성자 서명이 활성화된 경우 V2 서명 입력에도 결속됩니다. 열람기는 복호화 후 해시를 재계산하고 일치하지 않으면 페이로드를 거부합니다.
32바이트 콘텐츠 식별자 qub_id는 프로토콜 버전, 콘텐츠 유형, 생성 및 잠금 해제 타임스탬프, 선택적 판정 타임스탬프(또는 0 센티널), 대상 drand 라운드, 본문 해시, 선택적 NFC 정규화 제목의 SHA3-256을 포함하는 108바이트 사전 이미지에서 파생됩니다. 게이트웨이나 CDN은 결속된 필드를 일관되게 변경하면서 재도출 검증을 통과할 수 없습니다. 제목은 100 NFC 코드 포인트로 제한되며, bidi 재정의, 폭 없는 문자, 태그 블록, BOM, C0, C1, DEL을 포함한 공통 유해/제어 코드 포인트 클래스가 거부됩니다.
3.5 서명(ML-DSA-65)
작성자 서명은 NIST 표준화 포스트양자 서명 방식인 ML-DSA-65(FIPS 204)를 사용합니다. 저희는 봉인된 콘텐츠가 영구적이기 때문에 서명에 포스트양자 원시를 의도적으로 선택했습니다: 오늘 검증되는 서명은 수십 년 후에도, 대규모 양자 컴퓨터가 실용화된 후에도 여전히 검증되어야 합니다.
서명 키는 브라우저에서 생성됩니다. 로컬 비밀은 IndexedDB에 저장되기 전에 추출 불가능한 WebCrypto 키로 래핑됩니다. 계정 범위의 기기 간 복구 기능을 사용하면 AEAD로 암호화된 이동 가능한 키 블롭이 서버 측에 저장됩니다. 비밀 키 암호문은 변경 불가능한 계정 ID에 결속되고 서비스는 공개 엔벨로프를 검증하지만 비밀 자료는 복호화할 수 없습니다. 원시 개인 키 바이트는 서버에 전송되지 않습니다. 공개 키와 증명 기록은 검증 및 신원 표시에 사용하기 위해 저장됩니다.
동일한 브라우저 내 tlock 복호화가 qub 임베드 내부에도 적용됩니다: 봉인된 qub이 제3자 페이지의 <qub-embed>를 통해 렌더링될 때, 복호화는 여전히 열람자의 브라우저의 임베드 iframe에서 일어납니다. 임베드는 신뢰 모델을 변경하지 않습니다 — 평문은 qub 서버에서 절대 복호화되지 않습니다.
3.6 공개 귀속 — 옵트인
봉인된 qubs는 작성자가 명시적으로 첨부하기로 선택하지 않는 한 작성자에 대한 온체인 포인터를 운반하지 않습니다. qub을 봉인할 때 참조 앱은 날짜 선택 단계에서 "공개 귀속"이 활성화된 경우에만 Author 저장소 태그(서명 공개 키의 64자 16진수 지문)를 발행합니다. 토글이 꺼져 있으면 — 기본값 — Author 태그가 기록되지 않으며 qub은 영구 저장소에서 귀속되지 않습니다: 저장소에서 아무것도 업로드를 사용자의 핸들, 이메일 또는 다른 qubs에 연결하지 않습니다. 토글이 켜져 있으면 지문은 §6.3 / §10의 증명 사슬을 통해 사용자의 @handle로 해석되며 열람자 카운트다운은 공개 전 "Sealed by @{handle}"을 표시합니다.
이것은 항상 켜져 있는 Author 태그가 만들어낼 열거 위험에 대한 의도적인 가드입니다: 작성자의 지문을 학습한 제3자는 그렇지 않으면 그 태그로 영구 저장소를 검색하여 그 작성자의 전체 역사적 출력을 재구성할 수 있습니다. 옵트인 귀속은 그 채널을 닫습니다 — 작성자가 명시적으로 귀속하기로 선택한 qubs만 영구 저장소에서 지문 아래 나타납니다.
/u/{handle} 프로필 페이지는 인증된 신원 카드입니다 — 핸들, 선택적 표시 이름 + URL, "인증된 이메일" 알약(주소 없음), 그리고 암호학적 지문 짧은 형식. 작성자의 qubs를 나열하지 않습니다. 작성자의 특정 qub을 보고 싶은 방문자는 해당 qub의 전달 URL을 직접 따라갑니다.
3.7 외부 암호 래퍼
시한 해제 복호화가 수학적으로 가능해진 후—결속된 라운드의 drand 서명이 게시된 후—정규 시한 해제 계층만으로는 인덱서가 발견 가능한 qub을 대량 복호화할 수 있습니다. 비공개 전달은 시한 해제 암호화된 바이트 주위에 추가 대칭 계층을 두어 이 채널을 닫습니다(프로토콜 §13). 공개 전달은 알림, 임베드, 검색 링크가 비밀 프래그먼트 없이 작동할 수 있도록 의도적으로 래퍼를 생략합니다.
래퍼는 AES-256-GCM(NIST 표준화된 인증 암호)을 사용하며, 브라우저의 CSPRNG에 의해 qub당 신선한 256비트 키 K가 생성됩니다. K는 인증된 추가 데이터로 qub의 qub_id에 묶여 있어, 한 qub의 키가 다른 qub을 복호화하는 데 재사용될 수 없습니다.
기본 비공개 브라우저 흐름에서는 K가 저희 서버에 도달하지 않습니다. 공유 링크의 URL 프래그먼트(https://qub.social/c/<tx_id>#<base64url(K)>)에 인코딩됩니다. 브라우저는 URL 프래그먼트를 서버에 전송하지 않습니다—RFC 3986은 프래그먼트를 요청 외부에 둡니다—따라서 이 흐름에서 qub.social, 저장소 게이트웨이, CDN, 요청 모니터링은 K를 볼 수 없습니다. 저장된 OuterWrapper는 식별 가능한 구조화 CBOR이지만, 인증된 암호문 필드가 내부 SealedQub 구조를 숨기며 K 없이는 열 수 없습니다.
순 결과:
- qub.social은 저장 데이터만으로 기본 비공개 브라우저 봉인을 복호화할 수 없습니다. 데이터 저장소 침해로 K 없는 불투명한 암호문만 얻습니다. 공개 qub과 복구가 활성화된 qub은 설계상 노출 범위가 다릅니다.
- 옵트인 복구 채널이 없으면 프래그먼트 손실은 회복 불가능합니다. 프래그먼트 없이 비공개 링크를 저장했고 복구를 활성화하지 않았다면 해당 링크로 qub을 읽을 수 없습니다. 봉인 흐름은 이 이유로 명시적인 "이 URL을 저장하세요" 공개를 표시합니다.
- 옵트인 복구. qub에 대해 작성자 생명주기 이메일에 옵트인하고 이메일이 인증된 신원과 일치하면, 저희는 업로드와 함께 K를 받아들여 신원의 봉인 기록에 전체 전달 URL을 저장하고 봉인 확인 이메일의 링크로 사용합니다. 이 거래 — 일부 종단 간 순수성을 서버 측 복구 채널과 교환하는 것 — 는 명시적 옵트인에 대해서만 그리고 그 qub에 대해서만 동작합니다. 기본 자세는 암호-파쇄입니다.
Worker의 서버 측 /api/v1/seal 엔드포인트(AI 에이전트 및 다른 API 호출자가 사용)는 호출자가 CSPRNG로 K를 생성하고, 로컬에 보관하며, wrapper_key_b64url로 제공할 것을 요구합니다. Worker는 이 명시적으로 신뢰된 경로에서 평문과 K를 필연적으로 메모리에서 보게 되지만, 둘 중 어느 것도 영구 저장하지 않습니다. 필수 Idempotency-Key는 유실된 응답이 두 번째 과금 qub을 생성하는 것을 방지하며, 호출자가 보관한 K는 재생된 프래그먼트 없는 URL과 결합될 수 있습니다. 이는 기본 브라우저 경로와 다릅니다. 기본 브라우저 경로에서는 작성자가 복구를 명시적으로 활성화하지 않는 한 K가 Worker에 절대 도달하지 않습니다.
4. 전송 및 엣지
4.1 TLS
qub에 대한 브라우저 트래픽은 Cloudflare 엣지에서 HTTPS로 제공됩니다. 응답에는 HTTP Strict Transport Security(max-age=63072000; includeSubDomains; preload)가 설정됩니다. 정확한 협상 TLS 버전과 암호 스위트는 애플리케이션 코드가 단언하는 것이 아니라 활성 엣지 구성에 따릅니다. 별도로 직접 접근 가능한 원본 서버는 노출하지 않습니다.
4.2 콘텐츠 보안
컴파일된 클라이언트는 엄격한 콘텐츠 유형 및 캐시 헤더로 제공됩니다. SPA 셸은 단일 출처입니다. 저희는 분석이나 광고를 위한 제3자 스크립트를 임베드하지 않습니다. 제품의 두 제3자 접점은 모두 좁게 제한됩니다: 구매 흐름은 Stripe 호스팅 결제(https://checkout.stripe.com/…)로의 전체 페이지 리디렉션으로 SPA를 완전히 떠납니다 — Stripe의 UI는 저희 출처에서 실행되지 않으며 저희는 카드 데이터를 보지 않습니다 — 그리고 봉인 흐름은 Cloudflare의 자체 샌드박스된 iframe 내부에서 Cloudflare가 렌더링하는 개인정보 보호형 CAPTCHA 대안인 Cloudflare Turnstile 위젯을 로드합니다. 어느 쪽도 페이지의 나머지를 읽을 수 없습니다.
qub 임베드 iframe(qub.social/embed/{tx_id}에서 제공되고 embed.js에 의해 제3자 사이트에 로드됨)은 자체 Content-Security-Policy를 운반합니다. connect-src 허용 목록은 'self', https://qub.social, https://arweave.net, https://ar-io.dev, https://permagate.io, https://api.drand.sh, https://drand.cloudflare.com입니다. iframe은 sandbox="allow-scripts allow-top-navigation-by-user-activation"으로 실행되며 allow-same-origin은 없습니다. 호스트 페이지는 iframe의 DOM을 읽을 수 없고, iframe은 사용자 동작 이후에만 호스트를 탐색할 수 있습니다.
4.3 CORS 및 Fetch 범위
브라우저 클라이언트는 다음에만 fetch 요청을 합니다:
- 저희 자체 API(
api.qub.social및 스테이징 동등물) - 저장소 게이트웨이(래핑된 비공개 또는 래퍼 없는 공개 바이트 검색용 읽기 전용 — §3.6)
- drand 비콘 엔드포인트(공개 시 라운드 서명용 읽기 전용)
임베드 대상은 CSP로 강제됩니다. 주 SPA의 의도된 대상은 코드와 구성에 고정되고 브라우저 및 통합 검사로 시험됩니다. Subresource Integrity는 네트워크 대상 제어가 아닙니다.
임베드는 허용된 qub/저장소 출처를 통해 저장된 바이트를 가져오고, 비공개 페이로드는 URL 프래그먼트의 K를 사용해 브라우저에서 래퍼를 해제하며, 공개 시 라운드 서명은 허용된 두 drand 출처에서 가져옵니다. 주 SPA는 config/drand-endpoints.json의 네 엔드포인트 폴백 세트(drand.cloudflare.com, api.drand.sh, api2.drand.sh, api3.drand.sh)를 사용하므로 한 엔드포인트의 중단이 공개를 막지 않습니다. 임베드 CSP는 명시적 목록 밖의 연결을 거부합니다.
5. 서버 측 인프라
5.1 서버리스 엣지
저희 API는 엣지의 관리형 서버리스 런타임에서 완전히 실행됩니다. 저희가 관리하는 VM도, 컨테이너도, 영구 서버 프로세스도 없습니다. 이는 저희가 책임지는 공격 표면을 극적으로 줄입니다: 저희는 패치해야 하는 OS, 웹 서버 또는 애플리케이션 런타임을 실행하지 않습니다.
별도의 공개 CORS 미들웨어가 적용됩니다 Access-Control-Allow-Origin: * 다음에 구현된 경로 집합으로: /embed.js, /embed/v1.js, 그 아래의 모든 것 /embed/; /api/v1/telemetry; /api/v1/openapi.json; 모든 것 아래 /api/v1/qub/ (바이트, 메타데이터, 증거, 참여, 알림, 푸시 하위 경로 포함); 그 하위의 모든 것 /api/v1/log/; 공개 핸들 조회 하에 /api/v1/handle/; 그리고 공개 아바타가 아래에서 읽습니다 /api/v1/identity/avatar/. 그 사전 비행 허가 GET, POST, 그리고 OPTIONS 와 함께 Content-Type 요청 헤더. 이 접두사 기반 표면은 현재 임베드가 수행하는 호출만 포함하는 것보다 더 넓으므로, 해당 접두사 아래의 모든 핸들러는 자체 검증, 인증, 속도 제한 및 남용 통제를 계속 시행해야 합니다. 다른 API 경로는 qub.social 제한 CORS 정책을 유지합니다.
5.2 저장소
- 메타데이터 및 조정 저장소는 신원과 증명 기록, 자격 및 결제 참조, API 키 기록, 거부 목록 항목, 세션, 멱등성 상태, 큐, 비율 제한/동시성 상태를 보유합니다. 서로 다른 일관성 요구 사항에 따라 KV, D1, Durable Objects를 사용하며 하나의 범용 저장소를 사용하지 않습니다.
- 저희 객체 저장소도 내구성 기반입니다. 업로드 시 승인한 정확한 래핑 또는 래퍼 없는 qub 바이트, 투명성 로그 리프와 좌표 키 Merkle 노드, 앵커 자료, 구조화된 이벤트 로그, 응답/메타데이터 캐시를 보유합니다.
- 영구 공개 저장소는 투명성 로그 앵커를 보유하며, T3 경로 또는 지연 게시에서는 개별 qub 트랜잭션도 보유합니다. 저희는 해당 네트워크를 운영하지 않습니다. 비공개 브라우저 페이로드는 보유자가 K도 가지고 있지 않은 한 불투명하게 유지되며, 공개/래퍼 없는 페이로드에는 의도적으로 그 추가 링크 역량 계층이 없습니다.
기본 브라우저 메시지 흐름은 qub 인프라에 평문을 영구 저장하지 않습니다. Builder /api/v1/seal은 평문과 K를 메모리에서 처리하지만 어느 것도 영구 저장하지 않습니다. 약정 스테이징은 공동서명, 철회 또는 만료될 때까지 서명된 구조화 약정을 저장해야 합니다. 옵트인 복구는 나중에 복구할 수 있도록 전달 역량(프래그먼트가 포함된 전체 링크)을 저장합니다. 따라서 전체 저장 계층을 "메타데이터 전용"이라고 설명하지 않습니다.
5.3 비밀
비밀(서명 지갑, 제공업체 토큰, HMAC 키)은 소스 제어가 아니라 플랫폼 비밀/환경 바인딩을 통해 제공됩니다. 런타임 구성 요소는 필요한 바인딩만 받습니다. 교체 및 중첩 절차는 구성 요소마다 다르며, 하나의 범용 자동 또는 감사형 교체 메커니즘이 있다고 주장하지 않습니다.
5.4 로깅 및 텔레메트리
구조화된 JSON 로그는 모든 API 요청에 대해 X-Request-Id 응답 헤더에 표시되는 상관 ID와 함께 작성됩니다. 클라이언트 텔레메트리는 익명입니다 — 기기 식별자, IP 주소, 콘텐츠 미리보기 없음. 이벤트는 메모리에 버퍼링되고 최선 노력 기반으로 플러시됩니다; 실패한 플러시는 폐기되며 재시도되지 않습니다. 텔레메트리는 제품에 영향을 주지 않고 네트워크 계층에서 비활성화 가능하도록 설계되었습니다.
6. 인증
6.1 매직 링크 로그인
로그인은 이메일 받은편지함에 전달되는 일회용 HMAC 서명 토큰을 사용합니다. 링크는 15분간 유효하며, 교환은 원자적으로 청구되므로 동시 사용 또는 재생은 안전하게 실패합니다. 성공하면 브라우저는 Secure, HttpOnly, SameSite=Strict, Path=/ 속성이 있는 불투명한 __Host-qub_session 쿠키를 받습니다.
세션은 30일 유휴 제한과 90일 절대 제한을 두고, 24시간 후 교체되며, 응답 유실을 위한 120초 유예 동안 바로 이전 세대만 허용합니다. 민감한 계정 변경에는 지난 10분 이내의 인증이 필요합니다. HMAC 서명 비밀은 플랫폼 바인딩이며, 메타데이터 읽기만으로는 유효한 토큰을 만들 수 없습니다.
6.2 API 키(개발자 등급)
개발자 API 키는 쉬운 인식과 grep 가능성을 위해 접두어 qub_sk_를 사용합니다. 각 키는:
- 계정, 범위, 선택적 IP CIDR 허용 목록에 묶여 있습니다
- 원시 형식은 한 번만 표시되며, 영구 기록에는 Bearer 비밀이 아니라 SHA-256 해시가 보관됩니다
- 이전 키가 대체 키로 해석되는 1시간의 유예 매핑과 함께 교체할 수 있습니다
- 독립적인 할당량 및 비율 제한 상태를 갖습니다
- 절대로 전체로 로깅되지 않습니다; 로그는 키 식별자만 기록합니다
관리자 키 관리 엔드포인트는 별도의 관리자 자격 증명 뒤에 게이트됩니다.
6.3 이메일 증명(작성자 서명)
서명 키에 이메일 주소를 묶으려면 다음이 필요합니다:
- 개인 서명 키의 소유(챌린지에 서명)
- 이메일 받은편지함의 소유(이메일로 전달된 6자리 코드 입력)
어느 하나만으로는 불충분합니다. 철회는 본인 계정의 서명된 기록이며 즉시 적용됩니다; 증명을 가져오는 열람기는 철회된 상태를 보고 그에 따라 표시합니다.
7. 결제
카드 입력 및 처리는 Stripe 호스팅 결제에서 실행됩니다. 저희는 카드 번호, 만료일 또는 CVC를 받지 않습니다. 접근 권한, 갱신, 사용량 측정, 취소, 환불을 조정할 수 있도록 자격/API 키 기록에 Stripe 고객 및 구독 식별자, 구독 상태, 기간 데이터를 저장합니다. Stripe의 개인정보 및 보안 진술이 결제 데이터 처리를 관할합니다.
봉인 엔드포인트는 권한 기록을 기기 식별자와, 로그인한 사용자의 경우 연결된 신원과 교차 확인합니다. 권한은 사용자가 매직 링크 로그인을 통해 명시적으로 복원하지 않는 한 기기 간에 재사용될 수 없습니다.
8. 남용 저항
8.1 봇 감지
봉인 흐름은 추적용 쿠키를 사용하지 않으며 광고용 핑거프린팅을 하지 않는 개인정보 보호형 CAPTCHA 대안에 의해 게이트됩니다. 실패한 챌린지는 어떤 봉인 측 처리가 일어나기 전에 저희 엣지 Worker에 의해 거부됩니다.
8.2 비율 제한
비율 제한은 여러 계층에서 시행됩니다:
- 봉인, 읽기, 인증 엔드포인트의 IP당 및 키당 한도
- 매직 링크 요청의 이메일당 한도(받은편지함 범람 방지)
- 약정 초대 이메일의 상대방당 한도(수신자 주소당 UTC 일별 10건, 주요 스팸 릴레이 완화책; 정직한 약정은 거의 한도에 접근하지 않음)
- 텔레메트리 제출의 IP당 한도
카운터와 원자적 청구는 엔드포인트의 일관성 요구 사항에 따라 KV, Durable Objects, 플랫폼 비율 제한 바인딩에 분산됩니다. 비율 제한된 요청은 429를 반환하며, 재시도 시간을 계산할 수 있는 엔드포인트는 Retry-After를 포함합니다.
8.3 콘텐츠 모더레이션
기본 브라우저 업로드 경로는 본문을 스캔할 수 없습니다: 클라이언트에서 봉인된 아티팩트만 받습니다. 빌더 /api/v1/seal 경로는 일시적으로 평문을 보고, 계약 준비는 최종화될 때까지 구조화된 조건을 보유하지만, 이러한 신뢰 예외가 일반 바이트 블라인드 업로드 경로를 콘텐츠 스캐너로 바꾸지는 않습니다. 운영 상의 조정은 거부 목록 뷰어 계층에서: 거부 목록에 오른 qub는 저장된 페이로드에 여전히 접근할 수 있는지 여부와 관계없이 우리 뷰어에 의해 거부됩니다. 거부 목록에 올리는 것은 이미 게시된 내구성 바이트, 투명성 로그 항목, 또는 영구 네트워크 데이터를 철회하지 않습니다.
남용 신고는 신고자의 IP의 단방향 해시를 사용하여 비율 제한됩니다; 이 목적을 위해 평문 IP를 저장하지 않습니다.
9. 공급망 및 빌드 무결성
9.1 도구 체인 고정
컴파일러와 런타임 버전은 저장소 구성에 고정되고 의존성은 커밋된 잠금 파일을 통해 해석됩니다. CI는 생성 파일 최신 상태와 재현성에 민감한 불변을 검사합니다. 모든 지원 머신에서 깨끗한 빌드가 바이트 단위로 동일하다는 더 강한 주장은 하지 않습니다.
9.2 린트 및 정적 분석
워크스페이스는 가장 엄격한 린트 그룹을 deny 수준에서 활성화합니다. CI는 문서 링크 경고를 포함한 모든 경고를 빌드 실패로 취급합니다. 이는 의도적입니다: 저희는 미묘한 회귀에 대한 트립와이어로 린트 엄격성을 사용합니다.
9.3 CI 게이트
CI 워크플로는 포맷팅과 엄격한 린트, Rust·WASM/브라우저·Worker·임베드·API 테스트, 유형 검사, 코드 커버리지, 변이/불변 검사, 의존성 및 워크플로 정적 분석, i18n 키·커버리지·드리프트·유해 코드 포인트 검사, 생성 문서/API/지식 베이스 최신 상태, 문서 인벤토리와 내부 링크 검사, 스타일시트 및 번들 예산, OpenAPI 검증을 포괄합니다. 비용이 큰 일부 변이 작업은 모든 푸시가 아니라 예약 실행됩니다.
필수 작업 중 하나라도 실패하면 단일 필수 ci 종합 상태가 계속 실패합니다. 보호 브랜치와 배포 워크플로는 더 작은 별도 보안 게이트를 중복하는 대신 이 결과를 사용합니다.
9.4 변이 테스트
주간 작업은 보안 핵심 순수 모듈에 대해 변이 테스트를 실행합니다: 해싱, 정규 CBOR, 봉인, 잠금 해제, 와이어 형식 newtypes, 프로토콜 유형 검증기, 그리고 핸들 네임스페이스. 변이 테스트는 "우리 테스트 스위트가 미묘하게 잘못된 코드를 잡는가?"에 답합니다 — 변이된 구현이 여전히 모든 테스트를 통과하면, 저희는 테스트 커버리지 갭이 있다는 것을 알고 해결합니다.
9.5 Git 훅
로컬 훅(pre-commit, pre-push)은 회귀가 개발자의 기기를 떠나기 전에 잡히도록 CI 게이트를 반영합니다. 훅은 저장소 스크립트를 통해 설치됩니다; 저희 워크플로에서 우회되지 않으며 건너뛰는 경우 CI가 권위 있는 게이트입니다.
10. 테스팅
보안 핵심 코드는 세 가지 종류의 테스트를 운반합니다:
- 단위 테스트는 프로토콜 사양에서 파생된 테스트 벡터를 포함하여 알려진 입력에서 예상 동작을 검증합니다.
- 속성 테스트는 수천 개의 임의 입력을 생성하고 불변을 주장합니다: 정규 CBOR 왕복, 서명 검증 왕복, 이메일 바인딩 술어, 약정 인정 결정성.
- 교차 구현 테스트는 저희 클라이언트와 서버 구현이 정규 인코딩에서 바이트 단위로 일치함을 검증합니다. 이는 프로덕션에 도달하기 전에 두 구현 사이의 발산을 잡습니다.
11. 브랜치 및 릴리스 위생
기능 브랜치는 Gate 1 풀 리퀘스트를 통해서만 staging으로 진행됩니다. 필수 ci 통과, 해결되지 않은 변경 요청 없음, 병합 충돌 없음, 검토된 깨끗한 트리가 필요하며 스쿼시 후 브랜치를 삭제합니다. main은 Gate 2 staging → main 풀 리퀘스트를 통해서만 진행되고 병합 커밋으로 계보를 보존합니다. 직접 브랜치 푸시는 릴리스 워크플로가 아닙니다.
스테이징 및 프로덕션 배포는 CI 이후 각각 보호된 staging 및 main 브랜치 상태에서 트리거됩니다. 풀 리퀘스트 코드와 포크 자격 증명에는 배포 비밀이 제공되지 않습니다.
배포 워크플로에 사용되는 비밀은 저희 CI 플랫폼에 의해 배포 환경으로 범위가 지정됩니다. 포크의 풀 리퀘스트 워크플로에는 제공되지 않습니다.
12. 조율된 공개
qub에서 보안 취약점을 발견했다고 믿는 경우, 저희는 신속하게 듣고 신고를 전문적으로 처리할 것을 약속합니다.
- 제목 접두어
[SECURITY]로support@qub.social에 이메일을 보내세요. - 취약점, 재현 단계 및 개념 증명을 설명하세요.
- 공개하기 전에 합리적인 공개 창(일반적으로 90일)을 제공하세요.
- 본인 소유가 아닌 데이터에 접근하거나, 다른 사용자에 대한 서비스를 저하시키거나, 문제를 입증하는 데 필요한 것을 넘어 연구 중에 획득한 데이터를 보유하지 마세요.
저희는 영업일 3일 이내에 수신을 확인하고 조사 진행 상황을 알려드립니다. 귀하의 동의가 있으면 릴리스 노트에 신고자를 인정합니다.
12.1 Safe Harbor
귀하의 연구가 위의 규칙(선의의 조사, 다른 사용자 또는 서비스에 해를 끼치지 않음, 합리적인 공개 창)을 따르는 경우, 저희는 귀하에 대해 법적 조치를 취하지 않을 것이며, 법 집행 기관에 요청하지도 않을 것입니다. 저희는 귀하의 작업을 인가된 테스팅으로 취급하며, 다른 누군가가 아니라 귀하가 버그를 찾는 것을 선호합니다.
본 Safe Harbor는 다음에 적용됩니다:
- 라이브 qub.social 서비스에 대한 연구(그 목적으로 게시하는 테스트 픽스처가 아님).
- 저희가 게시한 바이너리 및 오픈소스 qub-core / qub-app 크레이트의 리버스 엔지니어링.
- qub에 영향을 미치는 모든 취약점 클래스 — 프로토콜, 애플리케이션, 인프라, 공급망.
qub 팀 구성원의 사회 공학, 서비스 거부 테스트 또는 문제를 입증하는 데 필요한 것을 넘어 다른 사용자의 데이터에 접근하는 것에는 적용되지 않습니다. 무언가가 Safe Harbor 내에 있는지 확실하지 않은 경우, 동일한 [SECURITY] 제목 접두어를 사용하여 먼저 문의하세요.
13. 정직한 한계
보안은 상태가 아니라 실천입니다. 직접 언급할 가치가 있는 한계가 있습니다:
- 저희는 작은 팀입니다. 저희의 검토 깊이는 대기업의 전담 애플리케이션 보안 기능과 일치하지 않습니다. 엄격한 자동화된 게이트와 최소한의 공격 표면으로 보완하지만, 무오성을 주장하지 않습니다.
- 저희 저장소 백엔드의 영구성은 일방향 문입니다. 실수로 봉인된 콘텐츠가 의도한 것보다 일찍 복호화 가능해지면, 되돌릴 수 없습니다. 저희는 봉인 흐름을 그에 상응하는 주의로 처리합니다.
- drand 네트워크는 외부 의존성입니다. drand의 치명적인 실패는 모든 qub의 공개 동작에 영향을 미칠 것입니다. 저희는 drand 건강을 모니터링하고 필요한 경우 체인 마이그레이션을 위한 비상 문서를 보유합니다. 2년 이상 앞의 잠금 해제 날짜에 대해, 봉인 시 확인 모달은 명시적 공개를 표시합니다: 장기 horizon qubs는 drand 체인 내구성에 의존하며, 미래의 drand 체인 마이그레이션은 qub을 잠금 해제하기 위해 복구 단계를 필요로 할 수 있습니다. 5년 이상 앞의 잠금 해제 날짜에 대해, 봉인이 진행되기 전에 이 위험을 읽고 수락했음을 확인하는 추가 상자를 체크해야 합니다.
- 저희가 의존하는 암호 원시는 표준화되어 있고 널리 검토되었지만, 암호는 발전합니다. 선택할 곳이 있는 곳(포스트양자 서명, 인증된 암호화)에서는 더 보수적인 옵션을 선택합니다.
14. 이 페이지의 변경
중대한 변경은 페이지 상단의 시행일을 업데이트하여 표시됩니다. 변경이 구체적인 보안 개선을 반영하는 경우, 공개 변경 로그에 간략히 설명합니다. 변경이 정책 명확화를 반영하는 경우, 무엇이 변경되었고 왜인지 설명합니다.
이 페이지의 모든 것에 대한 질문은 제목 접두어 [SECURITY]로 support@qub.social에 이메일을 보내세요.
15. 변경 로그
| 버전 | 시행일 | 요약 |
|---|---|---|
| 1.1 | 2026년 9월 23일 | 암호학적 주장, 전달 모드, 저장소, CSP, 세션, API 키, 결제, CI, 릴리스 워크플로를 구현된 시스템과 일치시켰습니다. |
| 1.0 | 2026년 5월 2일 | 최초 공개. |