Bảo mật
Mô hình bảo mật của chúng tôi trong một câu: không có gì trên máy chủ để tấn công. Mọi thứ dưới đây đều có thể kiểm chứng từ DevTools của bạn.
Kiến trúc
Trình tạo mã là ứng dụng trang đơn tĩnh được phục vụ từ Cloudflare Pages: không tài khoản người dùng, không xác thực, và không có đường dẫn mã backend nào trong luồng tạo mã. Mọi thao tác tạo QR, mã hóa, quét và kết xuất đều chạy hoàn toàn trong trình duyệt của bạn. Một điểm cuối serverless nhỏ nằm cạnh nó và được liệt kê ở đây thay vì giấu đi: /api/contact (biểu mẫu liên hệ, lưu trữ những gì bạn gửi trong Cloudflare D1 và gửi email cho chúng tôi). Nó không được gọi khi bạn tạo mã QR; công cụ kiểm tra an toàn URL là một sản phẩm riêng tại check.qr.abundera.ai. Kiểm tra xem mã QR có an toàn không
Mô hình mối đe dọa
Vì trình tạo mã không thu thập, lưu trữ hay truyền dữ liệu người dùng (hai điểm cuối nói trên chỉ xử lý những gì bạn chủ động gửi cho chúng), các mối đe dọa web phổ biến nhất, đánh cắp thông tin xác thực, vi phạm cơ sở dữ liệu, chiếm quyền phiên, tiêm lệnh phía máy chủ, không áp dụng cho nó. Bề mặt tấn công còn lại là gói tài sản tĩnh (HTML, CSS, JavaScript) được phục vụ từ nguồn gốc của chúng tôi. Chúng tôi thiết kế với các giả định:
- Xâm phạm nguồn gốc: kẻ tấn công thay thế một trong các tài sản được đóng gói của chúng tôi bằng tài sản độc hại. CSP dưới đây giới hạn bán kính thiệt hại; các token cache-buster giúp dễ dàng quay lại phiên bản đã biết là tốt.
- Đầu vào do người dùng cung cấp: payload QR, tên vCard, mật khẩu WiFi, hàng CSV theo lô, nội dung hình ảnh được quét. Mọi đường dẫn đầu vào đều được coi là không tin cậy khi hiển thị lại vào DOM.
- Hình ảnh do người dùng cung cấp: URL ảnh vCard và tải lên logo. Hình ảnh được kết xuất vào canvas, không bao giờ được nhúng vào DOM dưới dạng markup thô.
- Tiện ích mở rộng trình duyệt của bên thứ ba: ngoài phạm vi. Nếu một tiện ích mở rộng trong trình duyệt của bạn có quyền chỉnh sửa mọi trang, nó có thể chỉnh sửa trang của chúng tôi. Các đảm bảo của chúng tôi có hiệu lực khi trang được tải mà không bị chỉnh sửa.
Chính sách bảo mật nội dung, theo chỉ thị
Chính sách bên dưới được đọc từ file _headers đã triển khai khi trang này được dựng, nên nó không thể trôi dạt khỏi những gì máy chủ biên gửi đi. Xác minh trong tiêu đề phản hồi của bất kỳ yêu cầu nào.
Content-Security-Policy:
default-src 'self';
script-src 'self' https://abundera.ai 'wasm-unsafe-eval' https://challenges.cloudflare.com;
worker-src 'self' blob:;
style-src 'self' 'unsafe-inline' https://abundera.ai;
font-src 'self';
img-src 'self' data: blob: https:;
connect-src 'self' https: https://challenges.cloudflare.com;
frame-src 'self' https://challenges.cloudflare.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self'Mỗi chỉ thị cho phép chúng tôi làm gì và đánh đổi ở đâu:
default-src 'self', nền tảng cứng. Bất cứ điều gì chúng tôi không nới lỏng rõ ràng vẫn là same-origin.script-src 'self' https://abundera.ai 'wasm-unsafe-eval' https://challenges.cloudflare.com, không có<script>inline, không cóeval().abundera.ailà tên miền cha của chính chúng tôi và chỉ phục vụ một script dùng chung, bộ chọn ngôn ngữ.challenges.cloudflare.comlà widget Turnstile chỉ dùng trên /contact/.'wasm-unsafe-eval'được yêu cầu bởi đường dẫn biên dịch WebAssembly của thư viện encoder QR; nó KHÔNG cho phépeval()truyền thống. Kiểm tra trước khi triển khai của chúng tôi quét mọi trang HTML để tìm script inline và làm hỏng bản dựng.style-src 'self' 'unsafe-inline', một nhượng bộ thực sự. Bản xem trước QR của chúng tôi tính toán màu ở cấp độ pixel theo kiểu inline (thuộc tính style trên các mô-đun riêng lẻ). Danh sách cho phép dựa trên hash sẽ hoạt động nhưng sẽ thất bại ở bất kỳ cập nhật style nào mà không có triển khai. Đánh đổi: chúng tôi chấp nhận chính sách style yếu hơn một chút; style dù sao cũng không thể rò rỉ dữ liệu (CSS không có phạm viconnect-src).img-src 'self' data: blob: https:,data:cho các render QR inline,blob:cho URL tải xuống xuất khẩu,https:cho URL ảnh vCard và ảnh đại diện do người dùng cung cấp. URL do người dùng cung cấp không bao giờ thực thi, chỉ kết xuất. Lưu ý chỉ thị này cũng là một kênh đi ra: bất kỳ script nào chạy trên trang đều có thể yêu cầu một hình ảnh từ bất kỳ máy chủ HTTPS nào và đặt dữ liệu vào URL. Chúng tôi chấp nhận điều đó vì tính năng cần nó, và chúng tôi nói rõ điều này ở đây thay vì mô tả chính sách là kín tuyệt đối.connect-src 'self' https: https://challenges.cloudflare.com, dòng cần đọc kỹ nhất.https:là một scheme source: nó cho phépfetch(), XMLHttpRequest, WebSocket qua TLS, EventSource vàsendBeacon()tiếp cận bất kỳ nguồn gốc HTTPS nào, không chỉ những nguồn bạn gõ vào. Nó tồn tại để trường ảnh vCard và kiểm tra an toàn URL có thể lấy về địa chỉ bạn dán vào. Nó không ngăn được việc rò rỉ dữ liệu bởi một script độc hại; không chỉ thị CSP nào làm được điều đó một khi script đã chạy với quyền của chúng tôi. Điều ngăn rò rỉ dữ liệu là mã chúng tôi phát hành không thực hiện các yêu cầu như vậy, điều bạn có thể quan sát trong tab Network.frame-src 'self' https://challenges.cloudflare.com, chỉ widget Turnstile mới được phép nhúng khung.frame-ancestors 'none', không có trang web nào khác có thể nhúng chúng tôi. Ngăn chặn clickjacking.base-uri 'self', thẻ<base>được tiêm độc hại không thể chuyển hướng URL tương đối đến nguồn gốc của kẻ tấn công.form-action 'self', bất kỳ form được tiêm nào chỉ có thể gửi lại nguồn gốc của chúng tôi. Biểu mẫu liên hệ là form duy nhất gửi đi bất cứ đâu.
Những gì CSP không thể làm
CSP giới hạn nơi trình duyệt sẽ tải mã. Nó không kiểm tra mã đã tải làm gì. Nếu nguồn gốc của chúng tôi bị xâm phạm, mục đầu tiên trong mô hình mối đe dọa, script của kẻ tấn công sẽ chạy với cùng quyền như của chúng tôi, bao gồm các quyền connect-src và img-src ở trên. Các biện pháp phòng thủ của chúng tôi trước điều đó nằm ở phía trước CSP: các bản triển khai đi qua một tài khoản Cloudflare duy nhất với token có phạm vi giới hạn, tên file tài sản được băm theo nội dung nên một file bị thay thế sẽ làm thay đổi mọi URL tham chiếu đến nó, và service worker chỉ lưu vào cache các phản hồi GET same-origin. Bản tuyên ngôn mô tả trang web như đã phát hành. Đó không phải là tuyên bố rằng không trang web nào có thể gửi dữ liệu đi đâu đó, và chúng tôi muốn bạn quy trách nhiệm cho chúng tôi theo phát biểu hẹp hơn, có thể kiểm chứng được.
Các chính sách CSP khác nhau áp dụng cho /bio/* (nới lỏng img-src cho avatar do người dùng cung cấp) và /embed/* (nới lỏng frame-ancestors cho nhúng có chủ ý). Cả hai đều được ghi lại trong site/_headers.
Tiêu đề truyền tải và đóng khung
- HSTS:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload, 1 năm, tất cả tên miền con, đủ điều kiện cho danh sách preload HSTS. Việc hạ xuống HTTP bị từ chối bởi các trình duyệt tuân thủ. - X-Frame-Options: DENY, thừa so với CSP
frame-ancestors, được giữ để hỗ trợ các trình duyệt cũ hơn. - X-Content-Type-Options: nosniff, ngăn chặn các cuộc tấn công nhầm lẫn MIME.
- Referrer-Policy: strict-origin-when-cross-origin, các nhấp vào liên kết đi ra ngoài rò rỉ nguồn gốc nhưng không rò rỉ đường dẫn.
- Permissions-Policy:
camera=(self), microphone=(), geolocation=(), camera chỉ được phép cho máy quét của chúng tôi; mic và vị trí bị từ chối rõ ràng ngay cả khi được nhúng.
Service worker
Service worker của chúng tôi (site/sw.js) chỉ lưu vào cache các tài sản same-origin. Trình xử lý fetch từ chối rõ ràng các yêu cầu cross-origin và các phương thức không phải GET, bạn có thể đọc logic trong /sw.js (mã nguồn được phát hành đủ chưa nén để theo dõi). Các lần ghi vào cache được bọc trong event.waitUntil() để chúng không thể bị bỏ qua giữa điều hướng.
Làm sạch đầu vào
Mọi đường dẫn kết xuất chấp nhận đầu vào của người dùng đều coi nó là văn bản không tin cậy:
- Bản xem trước payload QR sử dụng
textContent, không phảiinnerHTML. - Các đích chia sẻ (clipboard,
navigator.share()) truyền văn bản người dùng dưới dạng chuỗi, không bao giờ dưới dạng markup. - Các xuất SVG được tạo từ thư viện encoder của chúng tôi; nội dung người dùng được mã hóa base64 vào
<image>xlink:href, không được tiêm dưới dạng các phần tử SVG. - Bản xem trước in sử dụng blob URL, không phải
document.write(). - Phân tích localStorage được bọc trong
try/catch, một mục nhập bị hỏng tạo ra một giá trị mặc định rỗng mới, không bao giờ là ngoại lệ có thể mở ra vào đường dẫn mã trực tiếp. - URL do người dùng cung cấp được hiển thị dưới dạng nút "Mở liên kết" bị giới hạn ở
http(s)://, các lược đồjavascript:vàdata:bị từ chối.
Tải hình ảnh cross-origin
Khi người dùng dán URL https: làm ảnh vCard hoặc logo, trình duyệt tải về theo CORS và danh sách cho phép img-src của CSP. Hình ảnh được kết xuất vào canvas. Nó không bao giờ trở thành DOM trực tiếp, không bao giờ chạy như mã, và không bao giờ đến nguồn gốc của chúng tôi, tải về là trình duyệt → hình ảnh từ xa, và kết quả được vẽ phía client. Kẻ tấn công kiểm soát URL hình ảnh từ xa có thể theo dõi rằng URL đã được tải (một dòng log trên máy chủ của họ) nhưng không thể rò rỉ bất cứ điều gì từ trang của chúng tôi.
Tính toàn vẹn tài nguyên con (SRI)
Tất cả JavaScript và CSS chúng tôi cung cấp đều là same-origin. Chúng tôi không tải script hoặc stylesheet của bên thứ ba, vì vậy hash SRI không áp dụng. Nếu chúng tôi từng tải tài sản của bên thứ ba, chúng tôi sẽ thêm thuộc tính SRI integrity vào đó và ghi lại quy trình cập nhật hash trong trang này.
Báo cáo lỗ hổng
Nếu bạn phát hiện vấn đề bảo mật ảnh hưởng đến Abundera QR, trong mã của chúng tôi, triển khai của chúng tôi, hoặc trong một phụ thuộc mà chúng tôi cung cấp, vui lòng báo cáo riêng tư đến security@abundera.ai. Chúng tôi hướng đến việc phân loại trong vòng 72 giờ. Bạn cũng có thể liên hệ qua thông tin liên lạc trong file /.well-known/security.txt của chúng tôi.
Chưa có chương trình thưởng lỗi
Hiện tại chúng tôi không cung cấp tiền thưởng, nhưng mọi báo cáo hợp lệ được xác nhận đều nhận được ghi nhận trong changelog và lời cảm ơn công khai của chúng tôi.
Xác minh những điều trên
Mọi tuyên bố trên trang này đều có thể kiểm chứng từ DevTools của trình duyệt mà không cần tin tưởng chúng tôi:
- CSP: DevTools → Network →
/→ Headers. Đọc tiêu đề phản hồiContent-Security-Policy. - HSTS + tiêu đề bảo mật: cùng chỗ, tất cả
Strict-Transport-Security,X-Frame-Options, v.v. đều hiển thị. - Không có cuộc gọi đi ra ngoài: DevTools → Network → Fetch/XHR. Tạo một QR. Xem số đếm dừng ở không.
- Phạm vi service worker: DevTools → Application → Service Workers. Xác minh nguồn script và danh sách tài sản được lưu vào cache.
- Không có cookie: DevTools → Application → Cookies. Trống.
- Hướng dẫn đầy đủ: phần xác minh của bản tuyên ngôn.
Liên hệ
Báo cáo bảo mật: security@abundera.ai