安全
我们的安全模型一句话概括:服务器上没有任何可被攻击的东西。以下所有内容均可通过您的 DevTools 验证。
架构
Abundera QR 是一个由 Cloudflare Pages 提供服务的静态单页应用程序。没有应用服务器、数据库、用户账户、身份认证、API 端点,也没有处理用户数据的后端代码路径。每个 QR 的生成、编码、扫描和渲染操作完全在您的浏览器内运行。
威胁模型
由于我们不收集、存储或传输任何用户数据,最常见的 Web 应用威胁, 凭证盗取、数据库泄露、会话劫持、服务器端注入, 均不适用。剩余的攻击面是从我们的源站提供的静态资产包(HTML、CSS、JavaScript)。我们的设计假设:
- 源站被攻陷:攻击者将我们捆绑的某个资产替换为恶意版本。下面的 CSP 限制了破坏范围;cache-buster 令牌使回滚到已知正常版本变得容易。
- 用户提供的输入:QR 载荷、vCard 姓名、Wi-Fi 密码、批量 CSV 行、扫描图片内容。每条输入路径在渲染回 DOM 时均被视为不可信。
- 用户提供的图片:vCard 照片 URL 和 Logo 上传。图片被渲染到 canvas 中,绝不作为原始标记嵌入 DOM。
- 第三方浏览器扩展:不在范围内。如果您浏览器中的扩展拥有修改每个页面的权限,它就能修改我们的页面。我们的保证在页面未被修改加载时有效。
内容安全策略, 按指令说明
当前策略(可在任意请求的响应头中验证):
Content-Security-Policy:
default-src 'self';
script-src 'self' 'wasm-unsafe-eval';
worker-src 'self' blob:;
style-src 'self' 'unsafe-inline';
font-src 'self';
img-src 'self' data: blob: https:;
connect-src 'self' https:;
frame-ancestors 'none';
base-uri 'self';
form-action 'self'每条指令的作用及其妥协之处:
default-src 'self', 硬性底线。任何未明确放宽的内容均保持同源限制。script-src 'self' 'wasm-unsafe-eval', 禁止内联<script>,禁止eval()。'wasm-unsafe-eval'是我们 QR 编码库的 WebAssembly 编译路径所需;它不允许传统的eval()。我们的预部署检查会扫描每个 HTML 页面是否有内联脚本,发现则构建失败。style-src 'self' 'unsafe-inline', 真实的妥协。我们的 QR 预览会内联计算像素级颜色(各模块上的 style 属性)。基于哈希的白名单可行,但在不部署的情况下更新样式就会失败。权衡:我们接受稍弱的样式策略;样式无法窃取数据(CSS 没有connect-src访问能力)。img-src 'self' data: blob: https:,data:用于内联 QR 渲染,blob:用于导出下载 URL,https:用于用户提供的 vCard 照片 URL。用户提供的 URL 只会渲染,不会执行。connect-src 'self' https:, fetch() 限制为我们自己的源站加上用户发起的 HTTPS 请求(例如扫描照片 URL)。防止通过 DNS / WebSocket / beacon 向任意主机泄露数据。frame-ancestors 'none', 其他网站无法嵌入我们。防止点击劫持。base-uri 'self', 恶意注入的<base>标签无法将相对 URL 重定向到攻击者的源站。form-action 'self', 任何注入的表单只能向我们自己的源站提交。我们没有向服务端发送数据的表单;这是双重保险。
/bio/*(为用户提供的头像放宽 img-src)和 /embed/*(为有意嵌入放宽 frame-ancestors)适用不同的 CSP 策略。两者均记录在 site/_headers 中。
传输与框架头
- HSTS:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload, 1年,所有子域,符合 HSTS 预加载列表条件。合规浏览器拒绝降级到 HTTP。 - X-Frame-Options: DENY, 与 CSP
frame-ancestors重复,为兼容旧版浏览器而保留。 - X-Content-Type-Options: nosniff, 防止 MIME 混淆攻击。
- Referrer-Policy: strict-origin-when-cross-origin, 外链点击会泄露源站但不泄露路径。
- Permissions-Policy:
camera=(self), microphone=(), geolocation=(), 摄像头仅允许我们自己的扫描器使用;麦克风和位置即使在嵌入时也被明确拒绝。
Service Worker
我们的 Service Worker(site/sw.js)只缓存同源资产。fetch 处理程序明确拒绝跨源请求和非 GET 方法, 您可以在 GitHub 上阅读逻辑。缓存写入被包裹在 event.waitUntil() 中,因此不会在导航中途被丢弃。
输入净化
每条接受用户输入的渲染路径均将其视为不可信文本:
- QR 载荷预览使用
textContent,而非innerHTML。 - 分享目标(剪贴板、
navigator.share())将用户文本作为字符串传递,而非标记。 - SVG 导出由我们的编码库生成;用户内容被 base64 编码到
<image>的xlink:href中,而非作为 SVG 元素注入。 - 打印预览使用 blob URL,而非
document.write()。 - localStorage 解析被包裹在
try/catch中, 损坏的条目会产生一个全新的空默认值,而非可能展开到实时代码路径的异常。 - 显示为 "打开链接" 按钮的用户提供 URL 被限制为
http(s)://,javascript:和data:协议被拒绝。
跨源图片获取
当用户粘贴一个 https: URL 作为 vCard 照片或 Logo 时,浏览器根据 CORS 和我们 CSP 的 img-src 白名单获取它。图片被渲染到 canvas 中。它永远不会成为实时 DOM,不会作为代码运行,也不会到达我们的源站, 获取操作是浏览器到远程图片,结果在客户端绘制。控制远程图片 URL 的攻击者可以追踪该 URL 被加载(其服务器上的一行日志),但无法从我们的页面窃取任何内容。
子资源完整性(SRI)
我们提供的所有 JavaScript 和 CSS 均为同源。我们不加载第三方脚本或样式表,因此 SRI 哈希不适用。如果我们将来加载第三方资产,我们将在其上添加 SRI integrity 属性,并在本页记录哈希更新流程。
报告漏洞
如果您发现影响 Abundera QR 的安全问题, 无论是在我们的代码、部署还是我们提供的依赖项中, 请私下向 security@abundera.ai 报告。我们的目标是在 72 小时内完成分类处理。您也可以通过 /.well-known/security.txt 文件中的联系方式联系我们。
暂无漏洞赏金
我们目前不提供有偿赏金,但每一份经确认的有效报告都将在更新日志中获得致谢,并收到我们公开的感谢。
验证以上所有内容
本页每项声明均可通过浏览器 DevTools 验证,无需信任我们:
- CSP:DevTools → Network →
/→ Headers。查看Content-Security-Policy响应头。 - HSTS 及安全头:同一位置,
Strict-Transport-Security、X-Frame-Options等均可见。 - 无出站请求:DevTools → Network → Fetch/XHR。生成一个 QR 码。观察计数保持为零。
- Service Worker 范围:DevTools → Application → Service Workers。验证脚本来源和缓存资产列表。
- 无 Cookie:DevTools → Application → Cookies。空的。
- 完整演示:宣言的验证部分。
联系方式
安全披露:security@abundera.ai