Keamanan
Model keamanan kami dalam satu kalimat: tidak ada apa pun di server yang bisa diserang. Semua yang ada di bawah ini dapat diverifikasi dari DevTools Anda.
Arsitektur
Generator ini adalah aplikasi satu halaman statis yang disajikan dari Cloudflare Pages: tidak ada akun pengguna, tidak ada autentikasi, dan tidak ada jalur kode backend di mana pun dalam alur pembuatan kode. Setiap operasi pembuatan, pengkodean, pemindaian, dan rendering kode QR berjalan sepenuhnya di dalam browser Anda. Satu endpoint serverless kecil berada di sampingnya dan disebutkan di sini alih-alih disembunyikan: /api/contact (formulir kontak, yang menyimpan apa yang Anda kirimkan di Cloudflare D1 dan mengirimkannya lewat email kepada kami). Endpoint ini tidak dipanggil saat Anda membuat kode QR; pemeriksa keamanan URL adalah produk terpisah di check.qr.abundera.ai. Periksa apakah kode QR aman
Model ancaman
Karena generator tidak mengumpulkan, menyimpan, dan mengirimkan data pengguna (dua endpoint di atas hanya menangani apa yang secara eksplisit Anda kirimkan), ancaman aplikasi web yang paling umum, pencurian kredensial, pelanggaran basis data, pembajakan sesi, injeksi sisi server, tidak berlaku padanya. Permukaan serangan yang tersisa adalah bundel aset statis (HTML, CSS, JavaScript) yang disajikan dari origin kami. Kami merancang dengan asumsi:
- Kompromi origin: penyerang mengganti salah satu aset terbundel kami dengan yang berbahaya. CSP di bawah membatasi radius ledakan; token cache-buster memudahkan pengembalian ke versi yang diketahui baik.
- Input yang disediakan pengguna: muatan QR, nama vCard, kata sandi WiFi, baris CSV batch, konten gambar yang dipindai. Setiap jalur input diperlakukan sebagai tidak tepercaya saat dirender kembali ke DOM.
- Gambar yang disediakan pengguna: URL foto vCard dan unggahan logo. Gambar dirender ke dalam kanvas, tidak pernah disematkan ke DOM sebagai markup mentah.
- Ekstensi browser pihak ketiga: di luar cakupan. Jika ekstensi di browser Anda memiliki izin untuk memodifikasi setiap halaman, ekstensi itu dapat memodifikasi halaman kami. Jaminan kami berlaku saat halaman dimuat tanpa modifikasi.
Kebijakan Keamanan Konten, per direktif
Kebijakan di bawah ini dibaca dari berkas _headers yang di-deploy pada saat halaman ini dibangun, sehingga tidak mungkin menyimpang dari apa yang dikirim oleh edge. Verifikasi di header respons permintaan apa pun.
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'Apa yang setiap direktif memungkinkan kami lakukan dan di mana berkompromi:
default-src 'self', lantai keras. Apa pun yang tidak kami longgarkan secara eksplisit tetap same-origin.script-src 'self' https://abundera.ai 'wasm-unsafe-eval' https://challenges.cloudflare.com, tidak ada<script>inline, tidak adaeval().abundera.aiadalah domain induk kami sendiri dan menyajikan satu skrip bersama, yaitu pemilih bahasa.challenges.cloudflare.comadalah widget Turnstile yang digunakan hanya di /contact/.'wasm-unsafe-eval'diperlukan oleh jalur kompilasi WebAssembly pustaka enkoder QR kami; ini TIDAK mengizinkaneval()tradisional. Pemeriksaan pra-deploy kami memindai setiap halaman HTML untuk skrip inline dan menggagalkan build.style-src 'self' 'unsafe-inline', konsesi nyata. Pratinjau QR kami menghitung warna tingkat piksel secara inline (atribut style pada modul individual). Daftar izin berbasis hash akan berfungsi tetapi akan gagal pada pembaruan gaya apa pun tanpa deploy. Kompromi: kami menerima kebijakan gaya yang sedikit lebih lemah; gaya bagaimanapun tidak dapat mengekstrak data (CSS tidak memiliki jangkauanconnect-src).img-src 'self' data: blob: https:,data:untuk render QR inline,blob:untuk URL unduhan ekspor,https:untuk URL foto vCard dan avatar yang disediakan pengguna. URL yang disediakan pengguna tidak pernah dieksekusi, hanya dirender. Perlu diketahui bahwa direktif ini juga merupakan saluran keluar: skrip apa pun yang berjalan di halaman ini bisa meminta gambar dari host HTTPS mana pun dan menyisipkan data ke dalam URL-nya. Kami menerima hal itu karena fitur ini membutuhkannya, dan kami menyebutkannya di sini alih-alih menggambarkan kebijakan ini seolah kedap sepenuhnya.connect-src 'self' https: https://challenges.cloudflare.com, ini yang perlu dibaca dengan cermat.https:adalah sumber skema: ini memungkinkanfetch(), XMLHttpRequest, WebSocket melalui TLS, EventSource, dansendBeacon()menjangkau origin HTTPS mana pun, bukan hanya yang Anda ketik. Ini ada agar kolom foto vCard dan pemeriksaan keamanan URL dapat mengambil alamat yang Anda tempel. Ini tidak mencegah eksfiltrasi oleh skrip berbahaya; tidak ada direktif CSP yang bisa melakukannya begitu skrip sudah berjalan sebagai kami. Yang mencegah eksfiltrasi adalah bahwa kode yang kami kirimkan tidak membuat permintaan semacam itu, yang bisa Anda amati di tab Network.frame-src 'self' https://challenges.cloudflare.com, hanya widget Turnstile yang boleh dibingkai (framed).frame-ancestors 'none', tidak ada situs lain yang dapat menyematkan kami. Mencegah clickjacking.base-uri 'self', tag<base>yang disuntikkan dengan berbahaya tidak dapat mengalihkan URL relatif ke origin penyerang.form-action 'self', formulir yang disuntikkan hanya dapat mengirim kembali ke origin kami. Formulir kontak adalah satu-satunya formulir yang benar-benar mengirim data ke mana pun.
Apa yang tidak bisa dilakukan CSP
CSP membatasi dari mana browser boleh memuat kode. CSP tidak memeriksa apa yang dilakukan oleh kode yang sudah dimuat. Jika origin kami pernah dikompromikan, item pertama dalam model ancaman, skrip penyerang akan berjalan dengan izin yang sama seperti kode kami, termasuk keleluasaan connect-src dan img-src di atas. Pertahanan kami terhadap hal itu berada di hulu CSP: deploy dilakukan melalui satu akun Cloudflare dengan token berlingkup, nama berkas aset di-hash berdasarkan konten sehingga berkas yang ditukar mengubah setiap URL yang merujuknya, dan service worker hanya menyimpan cache respons GET same-origin. Manifesto menggambarkan situs sebagaimana ia dikirimkan. Ini bukan klaim bahwa tidak ada halaman web yang bisa mengirim data ke suatu tempat, dan kami lebih suka Anda menuntut kami pada pernyataan yang lebih sempit dan dapat diperiksa ini.
Kebijakan CSP yang berbeda berlaku untuk /bio/* (longgarkan img-src untuk avatar yang disediakan pengguna) dan /embed/* (longgarkan frame-ancestors untuk penyematan yang disengaja). Keduanya didokumentasikan di site/_headers.
Header transport dan framing
- HSTS:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload, 1 tahun, semua subdomain, memenuhi syarat untuk daftar preload HSTS. Browser yang sesuai menolak downgrade ke HTTP. - X-Frame-Options: DENY, redundan dengan CSP
frame-ancestors, dipertahankan untuk cakupan browser lama. - X-Content-Type-Options: nosniff, mencegah serangan kebingungan MIME.
- Referrer-Policy: strict-origin-when-cross-origin, klik tautan keluar membocorkan origin tetapi bukan jalur.
- Permissions-Policy:
camera=(self), microphone=(), geolocation=(), kamera hanya diizinkan untuk pemindai kami sendiri; mikrofon dan lokasi secara eksplisit ditolak meskipun disematkan.
Service worker
Service worker kami (site/sw.js) hanya menyimpan aset same-origin dalam cache. Pengendali fetch secara eksplisit menolak permintaan cross-origin dan metode non-GET, Anda dapat membaca logikanya di /sw.js (sumbernya dikirimkan cukup tidak terminifikasi untuk diikuti). Penulisan cache dibungkus dalam event.waitUntil() sehingga tidak dapat dihapus di tengah navigasi.
Sanitasi input
Setiap jalur rendering yang menerima input pengguna memperlakukannya sebagai teks tidak tepercaya:
- Pratinjau muatan QR menggunakan
textContent, bukaninnerHTML. - Target berbagi (papan klip,
navigator.share()) meneruskan teks pengguna sebagai string, tidak pernah sebagai markup. - Ekspor SVG dibuat dari pustaka enkoder kami; konten pengguna dikodekan base64 ke dalam
<image>xlink:href, tidak disuntikkan sebagai elemen SVG. - Pratinjau cetak menggunakan URL blob, bukan
document.write(). - Penguraian localStorage dibungkus dalam
try/catch, entri yang rusak menghasilkan default kosong baru, tidak pernah pengecualian yang dapat terurai ke jalur kode langsung. - URL yang disediakan pengguna yang ditampilkan sebagai tombol "Buka tautan" dibatasi ke
http(s)://, skemajavascript:dandata:ditolak.
Pengambilan gambar cross-origin
Ketika pengguna menempelkan URL https: sebagai foto vCard atau logo, browser mengambilnya tunduk pada CORS dan daftar izin img-src CSP kami. Gambar dirender ke dalam kanvas. Gambar tidak pernah menjadi DOM langsung, tidak pernah dijalankan sebagai kode, dan tidak pernah mencapai origin kami, pengambilan adalah browser → gambar jarak jauh, dan hasilnya dilukis di sisi klien. Penyerang yang mengendalikan URL gambar jarak jauh dapat melacak bahwa URL tersebut dimuat (baris log di server mereka sendiri) tetapi tidak dapat mengekstrak apa pun dari halaman kami.
Integritas Subresource (SRI)
Semua JavaScript dan CSS yang kami kirimkan adalah same-origin. Kami tidak memuat skrip atau lembar gaya pihak ketiga, sehingga hash SRI tidak berlaku. Jika kami pernah memuat aset pihak ketiga, kami akan mengirimkan atribut integrity SRI padanya dan mendokumentasikan proses pembaruan hash di halaman ini.
Melaporkan kerentanan
Jika Anda menemukan masalah keamanan yang mempengaruhi Abundera QR, baik dalam kode kami, deployment kami, atau dalam dependensi yang kami kirimkan, harap laporkan secara pribadi ke security@abundera.ai. Kami bertujuan untuk melakukan triage dalam 72 jam. Anda juga dapat menghubungi kami melalui detail kontak di file /.well-known/security.txt kami.
Belum ada bug bounty
Kami saat ini tidak menawarkan hadiah berbayar, tetapi setiap laporan valid yang dikonfirmasi menerima kredit di changelog dan ucapan terima kasih publik kami.
Verifikasi hal di atas
Setiap klaim di halaman ini dapat diverifikasi dari DevTools browser Anda tanpa harus mempercayai kami:
- CSP: DevTools → Jaringan →
/→ Header. Baca header responsContent-Security-Policy. - HSTS + header keamanan: tempat yang sama, semua
Strict-Transport-Security,X-Frame-Options, dll. terlihat. - Tidak ada panggilan keluar: DevTools → Jaringan → Fetch/XHR. Buat QR. Perhatikan hitungan tetap di nol.
- Cakupan service worker: DevTools → Aplikasi → Service Workers. Verifikasi sumber skrip dan daftar aset yang di-cache.
- Tidak ada cookie: DevTools → Aplikasi → Cookie. Kosong.
- Panduan lengkap: bagian verifikasi manifesto.
Kontak
Pengungkapan keamanan: security@abundera.ai