Beveiliging
Ons beveiligingsmodel in één zin: er is niets op een server om aan te vallen. Alles hieronder is verifieerbaar vanuit je DevTools.
Architectuur
Abundera QR is een statische single-page applicatie geserveerd vanuit Cloudflare Pages. Er is geen applicatieserver, geen database, geen gebruikersaccounts, geen authenticatie, geen API-eindpunten en geen backend-codepad dat gebruikersdata verwerkt. Elke QR-generatie, -codering, -scan en -renderingoperatie wordt volledig in je browser uitgevoerd.
Dreigingsmodel
Omdat we geen gebruikersdata verzamelen, opslaan of verzenden, zijn de meest voorkomende webapp-bedreigingen, diefstal van inloggegevens, databaseinbreuk, sessie-hijacking, server-side injectie, niet van toepassing. Het resterende aanvalsoppervlak is de statische asset-bundel (HTML, CSS, JavaScript) die vanuit onze origin wordt geserveerd. We ontwerpen met de aanname:
- Origin-compromittering: een aanvaller vervangt een van onze gebundelde assets door een kwaadaardig exemplaar. CSP hieronder beperkt de blastradius; cache-buster tokens maken terugkeer naar een bekende goede versie eenvoudig.
- Door gebruikers ingevoerde invoer: QR-payloads, vCard-namen, wifi-wachtwoorden, batch-CSV-rijen, gescande afbeeldingsinhoud. Elk invoerpad wordt als niet-vertrouwd behandeld wanneer het terug naar de DOM wordt gerenderd.
- Door gebruikers ingevoerde afbeeldingen: vCard-foto-URL's en logo-uploads. Afbeeldingen worden in een canvas gerenderd, nooit als onbewerkte opmaak in de DOM ingesloten.
- Browserextensies van derden: buiten bereik. Als een extensie in je browser toestemming heeft om elke pagina te wijzigen, kan deze ook de onze wijzigen. Onze garanties gelden wanneer de pagina ongewijzigd wordt geladen.
Content Security Policy, per directive
Het huidige beleid (verifieer in Response-headers voor elk verzoek):
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'Wat elke directive ons toestaat en waar het compromissen biedt:
default-src 'self', de harde vloer. Alles wat we niet expliciet versoepelen, blijft same-origin.script-src 'self' 'wasm-unsafe-eval', geen inline<script>, geeneval().'wasm-unsafe-eval'is vereist door het WebAssembly-compilatiepad van onze QR-encoderbibliotheek; het staat traditioneleeval()NIET toe. Onze eigen pre-deploy-controle scant elke HTML-pagina op inline scripts en laat de build mislukken.style-src 'self' 'unsafe-inline', een echte concessie. Onze QR-preview berekent inline kleuren op pixelniveau (stijlattributen op afzonderlijke modules). Een hash-gebaseerde allowlist zou werken, maar zou mislukken bij elke stijlupdate zonder een deploy. Afweging: we accepteren het iets zwakkere stijlbeleid; styling kan toch geen data exfiltreren (CSS heeft geenconnect-src-bereik).img-src 'self' data: blob: https:,data:voor inline QR-renders,blob:voor export-download-URL's,https:voor door gebruikers opgegeven vCard-foto-URL's. Door gebruikers opgegeven URL's worden nooit uitgevoerd, alleen gerenderd.connect-src 'self' https:, fetch() is beperkt tot onze origin plus door gebruikers geïnitieerde HTTPS-fetches (bijv. het scannen van een foto-URL). Voorkomt exfiltratie via DNS / WebSocket / beacon naar willekeurige hosts.frame-ancestors 'none', geen andere site kan ons insluiten. Voorkomt clickjacking.base-uri 'self', een kwaadaardig geïnjecteerde<base>-tag kan relatieve URL's niet doorsturen naar de origin van een aanvaller.form-action 'self', elk geïnjecteerd formulier kan alleen terugposten naar onze origin. We hebben geen formulieren die data server-side verzenden; dit is een extra veiligheidslaag.
Verschillende CSP-beleidsregels zijn van toepassing op /bio/* (versoepelde img-src voor door gebruikers opgegeven avatars) en /embed/* (versoepelde frame-ancestors voor opzettelijk insluiten). Beide zijn gedocumenteerd in site/_headers.
Transport- en framing-headers
- HSTS:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload, 1 jaar, alle subdomeinen, in aanmerking komend voor de HSTS-preloadlijst. Downgrades naar HTTP worden geweigerd door conforme browsers. - X-Frame-Options: DENY, redundant met CSP
frame-ancestors, bewaard voor dekking van oudere browsers. - X-Content-Type-Options: nosniff, voorkomt MIME-verwarringsaanvallen.
- Referrer-Policy: strict-origin-when-cross-origin, uitgaande linkklikken lekken de origin maar niet het pad.
- Permissions-Policy:
camera=(self), microphone=(), geolocation=(), camera alleen toegestaan voor onze eigen scanner; microfoon en locatie expliciet geweigerd, ook bij insluiting.
Service worker
Onze service worker (site/sw.js) slaat alleen same-origin-assets in de cache op. De fetch-handler weigert expliciet cross-origin-verzoeken en niet-GET-methoden, je kunt de logica lezen op GitHub. Cache-schrijfbewerkingen zijn gewikkeld in event.waitUntil() zodat ze niet halverwege een navigatie kunnen worden verwijderd.
Invoersanitisatie
Elk renderingpad dat gebruikersinvoer accepteert, behandelt dit als niet-vertrouwde tekst:
- QR-payload-previews gebruiken
textContent, nietinnerHTML. - Share-doelen (klembord,
navigator.share()) geven gebruikerstekst door als een string, nooit als opmaak. - SVG-exports worden gegenereerd vanuit onze encoderbibliotheek; gebruikersinhoud is base64-gecodeerd in
<image>xlink:href, niet geïnjecteerd als SVG-elementen. - Afdrukpreviews gebruiken een blob-URL, niet
document.write(). - localStorage-parsing is gewikkeld in
try/catch, een corrupt item levert een vers leeg standaard op, nooit een uitzondering die in een live codepad kan terechtkomen. - Door gebruikers opgegeven URL's weergegeven als "Link openen"-knoppen zijn beperkt tot
http(s)://,javascript:endata:schema's worden afgewezen.
Cross-origin afbeeldingen ophalen
Wanneer een gebruiker een https:-URL plakt als vCard-foto of logo, haalt de browser deze op via CORS en de img-src-allowlist van onze CSP. De afbeelding wordt in een canvas gerenderd. Het wordt nooit live DOM, wordt nooit uitgevoerd als code en bereikt nooit onze origin, de fetch is browser → externe afbeelding en het resultaat wordt client-side geschilderd. Een aanvaller die een externe afbeeldings-URL beheert, kan bijhouden dat de URL is geladen (een logregel op hun eigen server), maar kan niets van onze pagina exfiltreren.
Subresource Integrity (SRI)
Alle JavaScript en CSS die we leveren is same-origin. We laden geen scripts of stylesheets van derden, dus SRI-hashes zijn niet van toepassing. Als we ooit een asset van een derde partij laden, zullen we een SRI integrity-attribuut eraan toevoegen en het hash-updateproces op deze pagina documenteren.
Een kwetsbaarheid melden
Als je een beveiligingsprobleem ontdekt dat Abundera QR treft, of het nu in onze code, onze implementatie of in een afhankelijkheid die we leveren zit, meld het dan privé aan security@abundera.ai. We streven ernaar binnen 72 uur te triageren. Je kunt ons ook bereiken via de contactgegevens in ons /.well-known/security.txt-bestand.
Nog geen bugbounty
We bieden momenteel geen betaalde bounties aan, maar elk bevestigd geldig rapport ontvangt erkenning in de changelog en onze publieke dankbaarheid.
Verifieer het bovenstaande
Elke bewering op deze pagina is verifieerbaar vanuit de DevTools van je browser zonder ons te vertrouwen:
- CSP: DevTools → Netwerk →
/→ Headers. Lees deContent-Security-Policy-responsheader. - HSTS + beveiligingsheaders: zelfde plaats, alle
Strict-Transport-Security,X-Frame-Options, enz. zijn zichtbaar. - Geen uitgaande oproepen: DevTools → Netwerk → Fetch/XHR. Genereer een QR. Kijk hoe het aantal op nul blijft.
- Service worker-bereik: DevTools → Applicatie → Service Workers. Verifieer de scriptbron en de lijst met gecachede assets.
- Geen cookies: DevTools → Applicatie → Cookies. Leeg.
- Volledige doorloop: de verificatiesectie van het manifest.
Contact
Beveiligingsmededelingen: security@abundera.ai