qub 安全
生效日期: 2026年9月23日 版本: 1.1 — 实施准确性审查
供研究人员参考 — 快速指南:
- 报告发送至: support@qub.social 带有主题前缀
[SECURITY].- 包括内容: 漏洞、重现步骤,以及任何概念验证。
- 我们的回应: 我们将在三个工作日内确认收到,并且目标是在九十天内发货修复。
- 安全港: 我们不会针对遵循第12条规则的善意研究采取法律行动(不得访问不属于你的数据,不得降低服务性能,不得保留超出展示问题所需的数据,并给予我们合理的披露时间)。
完整详情见第12条(协调披露)。
我们是谁
qub.social 由 VSPRY AUSTRALIA PTY LIMITED(ABN 41 631 026 330)运营,地址:Level 38, 71 Eagle Street, Brisbane QLD 4000, Australia。文中提到的"qub"、"我们"、"我们的"指代该实体。
安全联系方式:support@qub.social,邮件主题前缀 [SECURITY]。
1. 我们的方法
qub 是信任基础设施。如果它不安全,本产品就毫无价值,所以安全不是一个特性——它是底座。本页以具体术语描述了我们如何保障我们的技术栈、你的数据,以及已封印内容的完整性。
随着网络上越来越多的内容由机器生成,可验证的时间承诺的价值也在增长。一个经过验证的存储交易或透明日志锚可以证明密文最迟在其区块时间之前就存在;封存的产物则单独证明内容完整性、drand 轮次绑定以及任何作者签名。保持这些声明的区分,是本页面所遵循的标准。
我们不会要求你信任我们。我们的设计目标,是把对我们的信任要求降到尽可能小;而在确实需要信任的地方,我们会清楚说明被信任的是什么、以及为什么。
三条原则驱动着每一个设计决策:
- 将服务器可以看到的内容降到最低。 在默认浏览器消息流程中,明文和封装密钥保留在您的设备上。服务器端构建器封装、协议联合签署以及显式启用的恢复具有不同的信任边界,详见下文披露。对于我们持有的元数据,我们将其限制在所选功能所需的范围内。
- 使妥协局部化。 任何一个组件(我们的服务器、电子邮件提供商、一个 drand 节点)的泄露都不应揭示尚未到揭示时间的密封内容。
- 让协议可审计。 密封产物可使用公开密码学进行端到端验证;你无需信任 qub,也能验证 qub 产物。
2. 威胁模型
2.1 我们防护什么
- 在揭示时间之前,获得对我们存储的服务器端数据的读取访问权限的攻击者。 在默认的私有浏览器流程中,他们获得的是元数据和不透明的封装字节,而不是明文或 K。这种保护不适用于明确保留用于恢复的 K、在其 drand 轮次之后公开/裸露传递的 K,或临时提供给 Builder 的明文
/api/v1/seal以及 pact 工作流程。 - 拦截您浏览器与我们基础设施之间流量的攻击者。 TLS 在我们的 CDN 边缘终止;封装的有效载荷在传输前已经加密。
- 篡改存储载荷的攻击者。 外部包装认证(如果存在)、规范解码、正文哈希,
qub_id重新推导、轮绑定和可选签名使篡改无法通过验证;查看器拒绝呈现它。 - 试图将伪造的作者邮箱绑定到签名密钥的攻击者。 电子邮件认证需要同时拥有私有签名密钥和发送到邮箱的一次性代码。
- 一个被入侵的drand信标操作员。 drand 网络在多个独立运营商之间使用阈值 BLS 签名;少数人无法伪造提前发布的签名。
2.2 我们无法防护什么
我们坦诚说明我们的局限。qub 无法防御:
- 在你封存之前,你的设备已被妥协。 本地按键记录器、恶意浏览器扩展程序或对未锁定设备的物理访问都可能在文本输入点捕获明文。
- 分布式随机数阈值的崩溃。 多个独立的组织专门运行 drand 网络以增加这种难度,但这在密码学上并非不可能:如果足够多的运营者串通,他们可能会提前推导出时锁密钥。
- 有效副本的发布属性。 一个公共/裸的 qub 在其 drand 回合之后变得可解密。一个私有/包装的 qub 还需要 K;任何获得存储字节和 K 的人都可以在该回合之后进行解密。永久存储和锚定日志记录不能仅仅通过从 qub 的产品表面移除它们来回忆。
- 一个打破基础加密的全球对手 (AES-GCM、BLS12-381 配对假设、SHA3-256、ML-DSA-65)。如果这些原语失效,整个加密生态系统将面临更大的问题。
3. 客户端密码学
在默认的浏览器消息流程中,内容加密发生在上传请求之前。有两条明确的路径不同:Builder /api/v1/seal 故意将明文和调用者生成的 K 发送给 Worker 进行内存封装,而 pact 阶段/协签将已签名的结构化 pact 发送到服务,以便它可以完成双边产物。两者都不应被误认为是浏览器路径的端到端加密。
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 品牌字节序列。线缆格式有意做到品牌无关——任何符合规范的查看者(无论是我们的还是第三方的)都可以从永久存储渲染任意 qub,无关其由哪一个部署封印。该测试是一个绊线,防止未来的变更不慎将品牌引用烤进字节,而那些字节一旦进入永久存储就无法改写。
3.4 正文哈希与开启前完整性
每个封装的有效载荷都携带其原始主体字节的 SHA3-256 哈希。该哈希被绑定到 qub_id 并且,当启用作者签名时,会输入到 V2 签名输入中。查看者在解密后重新计算它,并拒绝不匹配的情况。
32字节内容标识符 qub_id 源自一个 108 字节的前映像,涵盖协议版本、内容类型、创建和解锁时间戳、可选的结果时间戳(或其零哨兵)、目标 drand 回合、主体哈希,以及可选 NFC 归一化标题的 SHA3-256。网关或 CDN 无法一致地更改任何绑定字段并仍通过重新派生。标题限制为 100 个 NFC 代码点,并且会拒绝共享敌对/控制代码点类(包括双向覆盖、零宽字符、标签块、BOM、C0、C1 和 DEL)。
3.5 签名(ML-DSA-65)
作者署名签名使用 ML-DSA-65(FIPS 204),一种由 NIST 标准化的后量子签名方案。我们刻意为签名选择了一个后量子原语,因为封印内容是永久的:今日能验证通过的签名,必须在数十年后——包括大规模量子计算机走向实用之后——仍能验证通过。
签名密钥在浏览器中生成。本地密钥在存储到 IndexedDB 前会被封装在一个不可导出的 WebCrypto 密钥下。如果使用基于账户的跨设备恢复功能,会在服务器端存储经过 AEAD 加密的可移植密钥块;其秘密密钥密文与不可变的账户 ID 绑定,服务端只验证公有封装,但无法解密秘密内容。原始私钥字节不会发送到服务器。公钥和证明记录会被存储用于验证和身份显示。
同一种浏览器内 tlock 解密同样适用于 qub 嵌入:当一条已封印的 qub 在第三方页面上通过 <qub-embed> 渲染时,解密仍发生在查看者浏览器中的嵌入 iframe 内。嵌入并未改变信任模型—— 明文永不会在 qub 服务器上被解密。
3.6 公开署名—— 可选
封印的 qub 不会携带指向其创作者的链上指针,除非创作者明示选择附加一个。当你封印一条 qub 时,参考创作者应用仅在日期选择步骤上启用"公开署名"时才会发出 Author 存储标签(你签名公钥的 64 字符十六进制指纹)。当开关关闭——默认状态——不会写入 Author 标签,且该 qub 在永久存储中未署名:存储中没有任何东西把这次上传与你的 handle、你的邮箱或你的其他 qub 关联起来。当开关打开时,指纹在查看者渲染时通过 §6.3 / §10 中的证明链解析为你的 @handle,倒计时在开启前会显示"由 @{handle} 封印"。
这是有意防范若 Author 标签始终开启会带来的枚举风险的一项保护:得到一位创作者指纹的第三方,否则可以按该标签在永久存储中做 grep,重建该创作者完整的历史输出。可选署名关闭了这条通道——只有创作者明示选择署名的那些 qub 才会以指纹形式出现在永久存储中。
/u/{handle} 个人页面是一张已验证身份卡—— handle、可选的显示名 + URL、"已验证邮箱"徽章(不显示地址),以及密码学指纹的简短形式。它不会列出某位创作者的 qub。希望查看某位创作者特定 qub 的访客,可直接通过该 qub 的传递链接前往。
3.7 外层加密包装
即使时间锁解密在数学上是可能的——一旦用于绑定轮次的 drand 签名被发布——单独的标准时间锁层也足以让索引器批量解密可发现的 qub。私有传递通过在时间锁加密的字节周围添加额外的对称层来关闭该通道(协议 §13)。公共传递故意省略该包装层,以便通知、嵌入和发现链接可以在没有秘密片段的情况下工作。
包装使用 AES-256-GCM,一种由 NIST 标准化的经认证密码,每条 qub 由你浏览器的 CSPRNG 生成一把新鲜的 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。出于这个原因,封印流程会显示一个明确的“保存此 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 严格传输安全(max-age=63072000; includeSubDomains; preload)。确切的协商 TLS 版本和加密套件由活动边缘配置决定,而不是由应用程序代码声明的。我们不公开单独可访问的源服务器。
4.2 内容安全
编译后的客户端以严格的 content-type 与缓存头进行服务。SPA 外壳是单一源。我们不为分析或广告嵌入第三方脚本。本产品中的两个第三方接触点都被严格限定:购买流程通过完整页面跳转完全离开 SPA 进入 Stripe 托管结账(https://checkout.stripe.com/…)—— Stripe 的 UI 永不在我们的源中执行,我们也永不看到卡数据;封印流程加载 Cloudflare 的 Turnstile 小部件,一种保护隐私的 CAPTCHA 替代方案,由 Cloudflare 在其自身沙箱化的 iframe 中渲染。两者都无法读取页面的其余部分。
这 qub 嵌入 iframe(从提供) qub.social/embed/{tx_id} 并由第三方网站加载 embed.js) 拥有自己的内容安全策略。它的 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): 主机页面无法读取其 DOM,并且除非用户操作,否则无法导航主机。
4.3 CORS 与抓取范围
浏览器客户端仅向以下目标发起抓取请求:
- 我们自己的 API (
api.qub.social以及分期等价物 - 存储网关(只读,用于包装私有或裸公共字节的检索 — §3.6)
- drand 信标端点(只读,用于揭示时间轮次签名)
嵌入的目标位置由其 CSP 强制执行。主 SPA 的预期目标位置在代码和配置中固定,并通过浏览器和集成检查进行验证;子资源完整性(Subresource Integrity)不是网络目标控制。
该嵌入通过允许的 qub/storage 源获取存储的字节,使用 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 完全运行在边缘的托管无服务器运行时上。没有虚拟机、没有容器,也没有由我们管理的常驻服务器进程。这极大地减小了我们需要负责的攻击面:我们不运行操作系统、不运行 Web 服务器,也不运行需要我们打补丁的应用运行时。
一个单独的公共 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,但不持久化任何一个。Pact 阶段必须存储已签名的结构化 pact,直到它被联合签署、撤回或过期。选择加入的恢复存储一个传递能力(完整的携带片段的链接),以便以后可以恢复。因此,我们不将整个存储层描述为“仅元数据”。
5.3 密钥
秘密(签名钱包、提供者令牌和 HMAC 密钥)通过平台秘密/环境绑定提供,而不是通过源代码管理。运行时组件只接收它们所需的绑定。轮换和重叠程序是组件特定的;我们不声称有单一的通用自动或审计轮换机制。
5.4 日志与遥测
每个 API 请求都写入结构化 JSON 日志,关联 ID 在 X-Request-Id 响应头中暴露。客户端遥测是匿名的——没有设备标识符、没有 IP 地址、没有内容预览。事件在内存中缓冲、按最大努力批量刷出;刷出失败即丢弃,不重试。遥测被设计为可以在网络层禁用而不影响产品。
6. 身份认证
6.1 Magic-Link 登录
登录使用通过 HMAC 签名的单次使用令牌,该令牌发送到您的电子邮箱收件箱。该链接有效期为 15 分钟,并且兑换是原子性申领的,因此同时或重复使用将失败。在成功后,浏览器会接收到一个不透明的 __Host-qub_session 带有……的饼干 Secure, HttpOnly, SameSite=Strict,和 Path=/ 属性。
会话有30天的空闲限制和90天的绝对限制,每24小时轮换一次,并且仅接受前一代以提供120秒的丢失响应宽限期。敏感账户变更要求在前10分钟内进行身份验证。HMAC签名密钥是平台绑定的;仅读取元数据本身不会生成有效令牌。
6.2 API 密钥(开发者层)
开发者 API 密钥使用前缀 qub_sk_,便于辨识与 grep。每把密钥:
- 绑定到一个账户、作用域,以及可选的 IP CIDR 允许列表
- 以原始形式显示一次;持久记录保留其 SHA-256 哈希,而不是持有者秘密
- 可以通过一小时的宽限映射进行旋转,其中旧密钥会解析到替换密钥
- 具有独立配额和速率限制状态
- 从不完整记录登录;日志仅记录关键标识符
管理员密钥管理端点由独立的管理员凭据保护。
6.3 邮箱证明(作者署名签名)
将邮箱地址与签名密钥绑定要求:
- 持有私签名密钥(你签一段挑战)
- 持有该邮箱(你输入通过邮件投递的 6 位数验证码)
任一项单独均不足够。撤销是写在你自己账号上的已签名记录,立即生效;查看者在抓取证明时会看到被撤销的状态并相应显示。
7. 支付
卡片输入和处理在 Stripe 托管的结账页面内进行。我们从不接收卡号、有效期或 CVC。我们确实会在权利/API 密钥记录中存储 Stripe 客户和订阅标识符、订阅状态以及周期数据,以便访问、续订、计量、取消和退款可以进行对账。Stripe 的隐私和安全声明管理其对支付数据的处理。
封印端点将权益记录与设备标识符交叉校验,对已登录用户还会与所链接的身份交叉校验。没有用户通过 magic-link 登录明示恢复,权益就无法在多设备间被复用。
8. 抗滥用
8.1 机器人检测
封印流程由一项保护隐私的 CAPTCHA 替代方案把关,它不为追踪使用 cookie,也不为广告进行指纹识别。挑战失败的请求会在任何与封印相关的处理发生之前被我们的边缘 Worker 拒绝。
8.2 限流
限流在多个层面执行:
- 对封印、读取与认证端点的按 IP 与按密钥限制
- 对 magic-link 请求的按邮箱限制(防止邮箱泛洪)
- 对约定邀请邮件的按对手方限制(每个收件人地址每个 UTC 日 10 封,是首要的垃圾邮件转发缓解;正当约定几乎从不接近该上限)
- 对遥测提交的按 IP 限制
计数器和原子声明根据端点的一致性要求分布在 KV、持久对象和平台速率限制绑定中。受速率限制的请求会返回 429;能够计算重试窗口的端点包括 Retry-After.
8.3 内容审核
默认的浏览器上传路径无法扫描主体:它只接收客户端封装的产物。构建器 /api/v1/seal 路由会短暂地看到明文,而协议分阶段会在最终确定之前保留结构化条款,但这些信任例外并不会将一般的字节盲上传路径变成内容扫描器。操作性管理是一个 拒绝列表 在查看器层:被拒绝列表的 qub 会被我们的查看器拒绝,无论存储的有效负载是否仍然可访问。拒绝列表不会撤回已经发布的持久字节、透明日志条目或永久网络数据。
滥用举报使用举报人 IP 的单向哈希进行限流;为此目的我们不以明文存储 IP。
9. 供应链与构建完整性
9.1 工具链固定
编译器和运行时版本在仓库配置中已固定,依赖关系通过提交的锁文件来解析。CI 检查生成文件的新鲜度和重现性敏感的不变性。我们并不声称每次干净构建在所有支持的机器上都是逐位相同的。
9.2 Lint 与静态分析
工作区在 deny 级别开启了我们最严格的 lint 组。CI 把每一条警告——包括文档链接警告——视为构建失败。这是刻意的:我们将严格的 lint 作为对细微回归的绊线。
9.3 CI 关卡
CI 工作流涵盖了格式化和严格的 lint 检查;Rust、WASM/浏览器、Worker、嵌入和 API 测试;类型检查;代码覆盖率;变异/不变性检查;依赖和工作流静态分析;i18n 键、覆盖率、漂移和恶意代码点检查;生成的文档/API/知识库的新鲜度;文档清单和内部链接检查;样式表和包大小预算;以及 OpenAPI 验证。一些开销较大的变异任务是安排好的,而不是在每次推送时运行。
单个必需 ci 如果任何必需的作业失败,roll-up 将保持为红色。受保护的分支和部署工作流会使用该结果,而不是重复一个较小的安全门。
9.4 变异测试
每周作业对安全关键的纯模块进行变异测试:哈希、规范化 CBOR、封印、开启、线缆格式的 newtype、协议类型校验器以及 handle 命名空间。变异测试回答"我们的测试套件是否能捕捉到细微错误的代码?"—— 如果被变异的实现仍然通过所有测试,我们就知道存在测试覆盖缺口并予以解决。
9.5 Git 钩子
本地钩子(pre-commit、pre-push)镜像 CI 关卡,从而回归在离开开发者机器之前就被捕获。钩子通过仓库脚本安装;它们不在我们的工作流中被绕过,并且如果它们被跳过,CI 是权威关卡。
10. 测试
安全关键代码携带三类测试:
- 单元测试在已知输入上验证预期行为,包括从协议规范导出的测试向量。
- 属性测试生成数千个任意输入并断言不变式:规范化 CBOR 往返、签名验证往返、邮箱绑定谓词、约定确认确定性。
- 跨实现测试验证我们的客户端与服务端实现在规范化编码上字节对字节一致。这在两套实现之间出现分歧到达生产之前就将其捕获。
11. 分支与发布卫生
功能分支前进 staging 仅通过 Gate 1 拉取请求:必需 ci 绿色,没有未解决的更改请求,没有合并冲突,并且审查过的分支是干净的;合并是压缩并删除。 main 只能通过大门2前进 staging → main 拉取请求并通过合并提交保留祖先记录。直接推送分支不是发布工作流。
暂存和生产部署是从相应的受保护触发的 staging 和 main CI 后的分支状态。拉取请求代码和分叉凭证不会获取部署密钥。
部署工作流中使用的密钥由我们的 CI 平台限定到部署环境。它们对来自 fork 的拉取请求工作流不可用。
12. 协调披露
如果你认为在 qub 中发现了安全漏洞,我们希望尽快听到——并承诺以专业方式处理这份报告。
- 发送邮件至
support@qub.social,主题前缀[SECURITY]。 - 描述漏洞、复现步骤以及任何概念验证。
- 在公开披露之前给我们一个合理的窗口期(通常为 90 天)。
- 不要访问不属于你的数据,不要降低其他用户的服务,不要保留在研究中所获数据多于证明问题所必需的部分。
我们会在三个工作日内确认收到,并在调查时让你知情。如得到你的同意,我们会在发布说明中署名致谢。
12.1 安全港
如果你的研究遵循上述规则(善意调查、不损害其他用户或服务、合理的披露窗口期),我们不会对你追究法律责任,也不会请求执法机构追究。我们视你的工作为获得授权的测试,并且更希望由你发现 bug,而不是别人。
本安全港适用于:
- 在 qub.social 实时服务上的研究(不包括我们为此公布的测试夹具)。
- 对我们公开发布的二进制文件与开源的 qub-core / qub-app crate 的逆向工程。
- 影响 qub 的任何漏洞类别——协议、应用、基础设施、供应链。
它不适用于对 qub 团队成员的社交工程、拒绝服务测试,或在为证明问题所必需之外访问其他用户数据。如果你不确定某事是否落入安全港范围,先用同样的 [SECURITY] 主题前缀来询问。
13. 诚实的局限
安全是一种实践,不是一种状态。有些局限值得直接命名:
- 我们是一个小团队。我们的审查深度无法匹配大公司专门的应用安全职能。我们以严格的自动化关卡与最小化的攻击面来补偿,但我们不宣称无懈可击。
- 我们存储后端的永久性是一扇单向门。如果一个错误导致封印内容比预期更早可解密,我们无法撤销。我们以相称的谨慎对待封印流程。
- drand 网络是一项外部依赖。drand 的灾难性故障会影响每一条 qub 的开启行为。我们监控 drand 健康状况,并在必要时为链迁移准备了应急文档。对于开启日期超过 2 年之后的 qub,封印时确认弹窗会展示明确披露:长期 qub 依赖于 drand 链的耐久性,未来的 drand 链迁移可能需要恢复步骤才能开启该 qub。对于开启日期超过 5 年之后的 qub,你必须额外勾选一个确认框,确认你已经阅读并接受该风险,封印才会继续。
- 我们依赖的密码学原语是经过标准化与广泛审查的,但密码学在演进。在有选择的地方(后量子签名、经认证加密),我们会选择更保守的那一种。
14. 本页的变更
实质性变更通过更新页面顶部的生效日期来标记。如果某项变更反映的是一项具体的安全改进,我们会在公开变更日志中简要描述。如果某项变更反映的是政策澄清,我们会描述变更了什么、为何变更。
对本页任何内容有疑问,请发送邮件至 support@qub.social,主题前缀 [SECURITY]。
15. 变更日志
| 版本 | 生效日期 | 摘要 |
|---|---|---|
| 1.1 | 2026年9月23日 | 将已实施系统与加密声明、传输模式、存储、云服务提供商、会话、API 密钥、支付、持续集成和发布工作流程进行了对齐。 |
| 1.0 | 2026年5月2日 | 初次出版。 |