Säkerhet hos qub

Ikraftträdandedatum: 23 september 2026 Version: 1.1 — gransking av implementeringsnoggrannhet


För forskare — snabb referens:

Fullständig information finns i §12 (Koordinerad offentliggörande).


Vilka vi är

qub.social drivs av VSPRY AUSTRALIA PTY LIMITED (ABN 41 631 026 330), Level 38, 71 Eagle Street, Brisbane QLD 4000, Australien. Hänvisningar till "qub", "vi", "oss" och "vår" avser den enheten.

Säkerhetskontakt: support@qub.social med ämnesprefixet [SECURITY].


1. Vårt tillvägagångssätt

qub är förtroendeinfrastruktur. Produkten är värdelös om den inte är säker, så säkerhet är inte en funktion — det är substratet. Denna sida beskriver, i konkreta termer, hur vi skyddar vår stack, din data och integriteten hos förseglat innehåll.

Värdet av ett verifierbart tidsbundet åtagande ökar i takt med att mer av internet blir maskingenererat. En verifierad lagringstransaktion eller ett transperenslogg-förankring kan fastställa att chiffertexten existerade senast vid dess blocktid; den förseglade artefakten bevisar separat innehållsintegritet, drand-rund-bindning och eventuella författarsignaturer. Att hålla dessa påståenden åtskilda är den standard som denna sida hålls till.

Vi ber dig inte lita på oss. Vi designar så att förtroendet som krävs av oss är så litet som möjligt, och där förtroende krävs förklarar vi exakt vad som anförtros och varför.

Tre principer driver varje designbeslut:


2. Hotmodell

2.1 Vad vi skyddar mot

2.2 Vad vi inte kan skydda mot

Vi är ärliga om våra gränser. qub kan inte försvara sig mot:


3. Klientsides-kryptografi

I standardflödet för webbläsarmeddelanden sker innehållskryptering innan uppladdningsbegäran. Två tydliga vägar skiljer sig: Builder /api/v1/seal skickar avsiktligt klartext och samtalsgenererat K till Arbete för in-memory-säkring, och pact-staging/co-signing skickar den signerade strukturerade pakten till tjänsten så att den kan slutföra den bilaterala artefakten. Ingen av dessa undantag bör förväxlas med webbläsarvägs end-to-end-kryptering.

3.1 Tidslås-kryptering

qub använder tlock — identitetsbaserad kryptering nycklad till en framtida drand-beacon-runda. Krypteringen fortsätter i din webbläsare med drand-nätverkets publika nyckel; dekrypteringsnyckeln släpps offentligt av drand-nätverket endast när målrundan nås. Ingen, inklusive vi, kan rekonstruera dekrypteringsnyckeln i förväg.

Vi siktar på quicknet-kedjan:

Quicknet-kedjans publika nyckel och genesistid är kompilerade in i klienten. Vi hämtar inte kedjeparametrar vid körtid, så en illvillig nod kan inte substituera en kedja vi kontrollerar.

3.2 Symmetrisk kryptering

tlock-schemat omsluter en AES-256-GCM-innehållsnyckel. AES-GCM tillhandahåller autentiserad kryptering: en enda bit som flippas i chiffertexten orsakar att dekryptering misslyckas, snarare än att producera tyst-korrumperad klartext.

3.3 Kanonisk serialisering

Protokollstrukturer serialiseras med deterministisk CBOR (RFC 8949 §4.2 kärndeterministisk kodning). Två implementationer som kodar samma logiska struktur producerar identisk CBOR. Fullständiga förseglade nyttolaster är inte deterministisk: tlock och outer-wrapper-kryptering använder färsk slumpmässighet. Kroppshashen beräknas över de råa kroppsbitarna, medan kanonisk kodning gör de omgivande signerade/tråddrar strukturerna entydiga.

Vi skrev CBOR-kodaren för hand för både vår klient- och serverimplementation snarare än att förlita oss på ett generiskt serialiseringsbibliotek — kravet är exakthet, inte ergonomi, och egenskapstester körs i båda implementationerna för att verifiera att de stämmer överens.

Ett regressionstest hävdar att det kanoniska wire-formatet inte innehåller någon qub-varumärkesbytesekvens utöver protokollprimitiv-qub_id-fältnyckeln. Wire-formatet är avsiktligt varumärkesagnostiskt — vilken konform läsare som helst (vår eller en tredje parts) kan rendera vilken qub som helst från permanent lagring, oavsett vilken distribution som förseglade den. Testet är en snubbeltråd som förhindrar att en framtida ändring av misstag bakar in en varumärkesreferens i byte som, när de väl är i permanent lagring, inte kan skrivas om.

3.4 Body-hashing och integritet före avslöjande

Varje förseglad nyttolast bär en SHA3-256-hash av sina råa kroppsbitar. Hashen är bunden till qub_id och, när författarskapssignering är aktiverad, i V2-signaturinmatningen. En visare beräknar om det efter dekryptering och avvisar en avvikelse.

Den 32-byte långa innehållsidentifieraren qub_id är härledd från en 108-byte förbild som täcker protokollversion, innehållstyp, skapad- och upplåsnings-tidsstämplar, valfri resultat-tidsstämpel (eller dess noll-sentinell), mål drand-runda, kropps-hash och SHA3-256 av den valfria NFC-normaliserade titeln. En gateway eller CDN kan inte ändra något bundet fält konsekvent och ändå klara om-beräkning. Titlar är begränsade till 100 NFC-kodpunkter och avvisas för den delade fiendtliga/kontroll-kodpunkts-klassen (inklusive bidi-överskridningar, noll-bredds tecken, taggblock, BOM, C0, C1 och DEL).

3.5 Signering (ML-DSA-65)

Författarskapssignering använder ML-DSA-65 (FIPS 204), ett NIST-standardiserat postkvantsignaturschema. Vi valde medvetet en postkvant-primitiv för signering eftersom förseglat innehåll är permanent: en signatur som verifierar idag måste fortfarande verifiera årtionden från nu, inklusive efter att storskaliga kvantdatorer blir praktiskt användbara.

Signeringsnycklar genereras i webbläsaren. Den lokala hemligheten omsluts under en icke-uttagbar WebCrypto-nyckel innan lagring i IndexedDB. Om funktionen för kontospecifik återställning mellan enheter används, lagras en AEAD-krypterad portabel nyckelblob på serversidan; dess hemliga nyckelkryptering är bunden till det oföränderliga konto-ID:t, och tjänsten validerar den offentliga kuvertet men kan inte dekryptera det hemliga materialet. Råa privata nyckel-bytes skickas inte till servern. Offentliga nycklar och attestationsposter lagras för verifiering och identitetsvisning.

Samma tlock-dekryptering i webbläsaren tillämpas inuti qub-embed:en: när en förseglad qub renderas genom <qub-embed> på en tredjepartssida sker dekrypteringen fortfarande i embed-iframe:n i läsarens webbläsare. Embed:en ändrar inte förtroendemodellen — klartext dekrypteras aldrig på en qub-server.

3.6 Offentlig attribuering — opt-in

Förseglade qubs bär ingen pekare på kedjan till sin skapare om inte skaparen uttryckligen väljer att bifoga en. När du förseglar en qub avger referensappen en Author lagringstag (en 64-tecken hex-fingeravtryck av din signerande publika nyckel) endast när "Offentlig attribuering" är aktiverad på datumväljarsteget. Med växeln av — standardvärdet — skrivs ingen Author-tag och qub:en är oattribuerad i permanent lagring: inget i lagringen länkar uppladdningen till ditt handtag, din e-post eller dina andra qubs. Med växeln på löses fingeravtrycket till ditt @handle via attesteringskedjan i §6.3 / §10 och läsarnedräkningen visar "Förseglad av @{handle}" före avslöjandet.

Detta är ett medvetet skydd mot uppräkningsrisken som en alltid-på Author-tag skulle skapa: en tredje part som lär sig en skapares fingeravtryck skulle annars kunna söka i permanent lagring efter taggen och rekonstruera den skaparens fullständiga historiska produktion. Opt-in-attribuering stänger den kanalen — endast qubs som skaparen uttryckligen väljer att attribuera dyker upp under ett fingeravtryck i permanent lagring.

Profilsidan /u/{handle} är ett verifierat-identitetskort — handtag, valfritt visningsnamn + URL, "verifierad e-post"-piller (ingen adress) och den kryptografiska fingeravtrycks-kortformen. Den listar inte en skapares qubs. Besökare som vill se en specifik qub från en skapare följer den qub:ens leveransurl direkt.

3.7 Yttre krypteringsomslag

Även efter att timelock-dekryptering är matematiskt möjlig—när drand-signaturen för den bundna rundan har publicerats—skulle det kanoniska timelock-lagret ensamt låta en indexer bulkdekryptera upptäckbara qubs. Privat leverans stänger den kanalen med ett ytterligare symmetriskt lager runt de timelock-krypterade byten (Protokoll §13). Offentlig leverans utelämnar medvetet omslaget så att notis-, inbäddnings- och upptäcktslänkar kan fungera utan en hemlig fragment.

Omslaget använder AES-256-GCM, ett NIST-standardiserat autentiserat chiffer, med en färsk 256-bitars nyckel K genererad per qub av din webbläsares CSPRNG. K är bunden till qub:ens qub_id som autentiserad ytterligare data, så en nyckel från en qub kan inte återanvändas för att dekryptera en annan qub.

K når aldrig våra servrar i standardflödet för privat webbläsare. Det är kodad i URL-fragmentet i delningslänken (https://qub.social/c/<tx_id>#<base64url(K)>). Webbläsare överför inte URL-fragment till servrar—RFC 3986 placerar fragmentet utanför förfrågan—så qub.social, lagringsgateways, CDN:er och förfrågningsövervakning är blinda för K i det flödet. Den lagrade OuterWrapper är igenkännbar strukturerad CBOR, men dess autentiserade chiffertextfält döljer det inre SealedQub struktur och kan inte öppnas utan K.

Nettokonsekvenser:

Worker:ns serverbaserade /api/v1/seal-endpoint (används av AI-agenter och andra API-anropare) kräver att anroparen genererar K med en CSPRNG, behåller den lokalt och tillhandahåller den som wrapper_key_b64url. Worker:n ser med nödvändighet både klartext och K i minnet på denna uttryckligen betrodda väg, men behåller ingendera. En obligatorisk Idempotency-Key förhindrar att ett förlorat svar skapar en andra debiterad qub, medan anroparens behållna K kan kombineras med den återspelade fragmentlösa URL:en. Detta skiljer sig från den förvalda webbläsarvägen, där K aldrig når Worker:n om inte skaparen uttryckligen aktiverar återställning.


4. Transport och kant

4.1 TLS

Webbläsartrafik till qub levereras över HTTPS vid Cloudflares kant. Svar sätter HTTP Strict Transport Security (max-age=63072000; includeSubDomains; preload). Den exakt förhandlade TLS-versionen och chiffersutten styrs av den aktiva edge-konfigurationen snarare än att fastställas av applikationskoden. Vi exponerar inte en separat åtkomlig ursprungsserver.

4.2 Innehållssäkerhet

Den kompilerade klienten serveras med strikta content-type- och cache-headers. SPA-skalet är ett enda ursprung. Vi bäddar inte in tredjepartsskript för analys eller annonsering. De två tredjeparts-beröringspunkterna i produkten är båda smalt avgränsade: köpflödet lämnar SPA:n helt med en helsidesomdirigering till Stripe-hostad kassa (https://checkout.stripe.com/…) — Stripes UI körs aldrig i vårt ursprung och vi ser aldrig kortdata — och förseglingsflödet laddar Cloudflares Turnstile-widget, ett integritetsbevarande CAPTCHA-alternativ som Cloudflare renderar inuti sin egen sandlådade iframe. Ingen av parterna kan läsa resten av sidan.

Den qub bädda in iframe (tjänstgjord från qub.social/embed/{tx_id} och laddades upp på webbplatser från tredje part av embed.js) har sin egen Content-Security-Policy. Dess connect-src vitlista är 'self', https://qub.social, https://arweave.net, https://ar-io.dev, https://permagate.io, https://api.drand.sh, och https://drand.cloudflare.com. Iframen körs med sandbox="allow-scripts allow-top-navigation-by-user-activation" (inte allow-same-origin): värdsidan kan inte läsa sitt DOM, och den kan inte navigera värden utom efter en användaråtgärd.

4.3 CORS och hämtningsomfång

Webbläsarklienten gör hämtningsförfrågningar endast till:

Inbäddningens destinationer styrs av dess CSP. Huvud-SPA:ns avsedda destinationer är fasta i kod och konfiguration och testas av webbläsar- och integrationskontroller; Subresource Integrity är ingen kontroll för nätverksdestinationer.

Inbäddningen hämtar lagrade bytes genom de tillåtna qub/storage-ursprungen, packar upp privata nyttolaster i webbläsaren med hjälp av K från dess URL-fragment och hämtar avslöjningstidsrundsignaturer från de två tillåtna drand-ursprungen. Huvud-SPA använder den fyrpunktsåterställningsuppsättning som är inställd i config/drand-endpoints.json (drand.cloudflare.com, api.drand.sh, api2.drand.sh, och api3.drand.sh) så att ett avbrott på en slutpunkt inte blockerar avslöjandet. Den inbäddade CSP:n nekar anslutningar utanför dess uttryckliga lista.


5. Serverbaserad infrastruktur

5.1 Serverlös kant

Vårt API körs helt på en hanterad serverlös körtid vid kanten. Det finns inga VM:er, inga containrar och inga persistenta serverprocesser som vi administrerar. Detta minskar dramatiskt attackytan som vi är ansvariga för: vi kör inget OS, ingen webbserver eller applikationskörtid som vi måste patcha.

Ett separat public-CORS-mellanmjukvara tillämpas Access-Control-Allow-Origin: * till den följande implementerade sökvägen: /embed.js, /embed/v1.js, allt under /embed/; /api/v1/telemetry; /api/v1/openapi.json; allt under /api/v1/qub/ (inklusive bytes, metadata, bevis, engagemang, notifiera och push-underrutter); allt under /api/v1/log/; offentliga hanteringsuppslag under /api/v1/handle/; och offentlig avatar läser under /api/v1/identity/avatar/. Dess förflygnings-tillstånd GET, POST, och OPTIONS med den Content-Type begäranhuvud. Denna prefixbaserade yta är bredare än endast de anrop som inbäddningen för närvarande gör, så varje hanterare under dessa prefix måste fortsätta att upprätthålla sin egen validering, autentisering, hastighetsbegränsningar och missbrukskontroller. Andra API-vägar behåller qub.social-begränsad CORS-policy.

5.2 Lagring

Standardmeddelandeflödet för webbläsaren lagrar inte okrypterad text på qub-infrastrukturen. Builder /api/v1/seal hanterar klartext och K i minnet men sparar varken. Pact-staging lagrar nödvändigtvis den signerade strukturerade paktet tills det medunderskrivs, återtas eller upphör. Frivillig återställning lagrar en leveranskapabilitet (den fullständiga fragmentbärande länken) så att det kan återställas senare. Vi beskriver därför inte hela lagringsnivån som "endast metadata."

5.3 Hemligheter

Hemligheter (signeringsplånböcker, leverantörstoken och HMAC-nycklar) tillhandahålls genom plattformshemligheter/miljöbindningar snarare än källkontroll. Körningens komponenter får endast de bindningar de behöver. Rotations- och överlappningsprocedurer är komponent-specifika; vi hävdar inte en enda universell automatisk eller granskad rotationsmekanism.

5.4 Loggning och telemetri

Strukturerade JSON-loggar skrivs vid varje API-förfrågan med en korrelations-ID som visas i X-Request-Id-svarsheadern. Klienttelemetri är anonym — ingen enhetsidentifierare, ingen IP-adress, ingen innehållsförhandsvisning. Händelser buffras i minnet och spolas på bästa-möjliga-basis; en misslyckad spolning kastas, försöks inte igen. Telemetri är designad för att kunna inaktiveras på nätverkslagret utan att påverka produkten.


6. Autentisering

6.1 Magic-link-inloggning

Inloggning använder en engångs-URL, HMAC-signerad token som skickas till din e-postinkorg. Länken är giltig i 15 minuter och inlösningen görs atomiskt, så samtidig eller upprepad användning misslyckas. Vid framgång mottar webbläsaren en ogenomskinlig __Host-qub_session kaka med Secure, HttpOnly, SameSite=Strict, och Path=/ attribut.

Sessioner har en inaktivitetgräns på 30 dagar och en absolut gräns på 90 dagar, roteras efter 24 timmar och accepterar endast den omedelbart föregående generationen för en 120-sekunders förlorad-svar-godkännandeperiod. Känsliga kontoförändringar kräver autentisering inom de föregående 10 minuterna. HMAC-signeringshemligheten är en plattformsbindning; en metadata-endast läsning skapar inte i sig en giltig token.

6.2 API-nycklar (utvecklarnivå)

Utvecklar-API-nycklar använder prefixet qub_sk_ för enkel igenkänning och grep-barhet. Varje nyckel:

Admin-nyckelhanterings-endpoints är spärrade bakom en separat admin-credential.

6.3 E-postattestering (författarskapssignering)

Att binda en e-postadress till en signeringsnyckel kräver:

  1. Innehav av den privata signeringsnyckeln (du signerar en utmaning)
  2. Innehav av e-postinkorgen (du anger en 6-siffrig kod levererad via e-post)

Endera ensamt är otillräckligt. Återkallelse är ett signerat register på ditt eget konto och träder i kraft omedelbart; läsare som hämtar attesteringen ser det återkallade tillståndet och visar därefter.


7. Betalningar

Kortinmatning och bearbetning körs i Stripe-hostade betalningsflöden. Vi tar aldrig emot kortnummer, utgångsdatum eller CVC. Vi lagrar dock Stripe-kund- och prenumerationsidentifierare, prenumerationstillstånd och perioddata på behörighets-/API-nyckelposter så att åtkomst, förnyelser, mätning, avbokning och återbetalningar kan stämmas av. Stripes sekretess- och säkerhetsuttalanden styr dess hantering av betalningsdata.

Förseglings-endpoint:en korsverifierar behörighetsregistret mot enhetsidentifieraren och, för inloggade användare, mot den länkade identiteten. En behörighet kan inte återanvändas över enheter utan att användaren uttryckligen återställer den via magic-link-inloggning.


8. Missbruksmotstånd

8.1 Botdetektering

Förseglingsflödet är skyddat av ett integritetsbevarande CAPTCHA-alternativ som inte använder cookies för spårning och inte gör fingeravtryck för annonsering. En misslyckad utmaning avvisas av vår kant-Worker innan någon förseglingssidesbehandling sker.

8.2 Hastighetsbegränsning

Hastighetsgränser tillämpas på flera lager:

Räknare och atomära krav är distribuerade över KV, Durable Objects och plattformsbegränsningar för hastighet enligt slutpunktens konsistenskrav. Begäranden som överskrider hastighetsgränsen returnerar 429; slutpunkter som kan beräkna ett återförsöksfönster inkluderar Retry-After.

8.3 Innehållsmoderation

Standardvägen för webbläsaruppladdning kan inte skanna kroppen: den tar endast emot det klientförseglade artefaktet. Byggaren /api/v1/seal rutten ser klartext tillfälligt, och pact-staging håller strukturerade villkor tills slutförande, men de där undantagen för förtroende förvandlar inte den allmänna byte-blinda uppladdningsvägen till en innehållsscanner. Operativ moderering är en avvisningslista på tittarlagret: en blocklistad qub nekas av vår tittare oavsett om den lagrade nyttolasten fortfarande är åtkomlig. Blocklistning återkallar inte beständiga bytes, transparens-loggposter eller redan publicerade permanenta nätverksdata.

Missbruksrapporter hastighetsbegränsas med en envägshash av rapportörens IP; vi lagrar inte IP:er i klartext för detta syfte.


9. Försörjningskedja och byggintegritet

9.1 Verktygskedjepinning

Kompilator- och körningstidsversioner är fastställda i repository-konfigurationen och beroenden löses genom incheckade låsfil. CI kontrollerar att genererade filer är aktuella och att reproducerbarhetskänsliga invariant hålls. Vi gör inte det starkare påståendet att varje ren byggning är bit-för-bit identisk över alla stödda maskiner.

9.2 Lintar och statisk analys

Arbetsytan aktiverar våra striktaste lintgrupper på deny-nivå. CI behandlar varje varning — inklusive dokumentations-länk-varningar — som ett byggfel. Detta är medvetet: vi använder lint-strikthetens som en snubbeltråd för subtila regressioner.

9.3 CI-grindar

CI-arbetsflödet täcker formatering och strikt lintning; Rust-, WASM/ webbläsar-, Worker-, embed- och API-tester; typkontroll; kodtäckning; mutation-/invariantkontroller; beroende- och arbetsflödesstatisk analys; i18n-nycklar, täckning, avvikelse och kontroller av fientliga kodpunkter; genererad dokumentation/API/kunskapsbasens uppdatering; dokumentinventering och interna länk-kontroller; stilark och bundle-budgetar; samt OpenAPI-validering. Vissa kostsamma mutationsjobb är schemalagda snarare än att köras vid varje push.

Ett enda obligatoriskt ci roll-up förblir röd om någon obligatorisk uppgift misslyckas. Arbetsflöden för skyddade grenar och distribution använder det resultatet istället för att duplicera en mindre säkerhetsgrind.

9.4 Mutationstestning

Ett veckojobb kör mutationstestning mot de säkerhetskritiska rena modulerna: hashning, kanonisk CBOR, försegla, packa upp, wire-format-newtypes, protokolltypvalidatorer och handtagsnamnrymden. Mutationstestning besvarar "fångar vår testsvit subtilt felaktig kod?" — om en muterad implementation fortfarande passerar alla tester vet vi att vi har en testtäckningslucka och åtgärdar den.

9.5 Git-hooks

Lokala hooks (pre-commit, pre-push) speglar CI-grindarna så att regressioner fångas innan de lämnar utvecklarens maskin. Hooks installeras via ett förrådsskript; de kringgås inte i vårt arbetsflöde och CI är den auktoritativa grinden om de hoppas över.


10. Testning

Säkerhetskritisk kod bär tre sorters tester:


11. Gren- och release-hygien

Funktionsgrenar går framåt staging endast genom en Gate 1 pull-begäran: obligatoriskt ci grön, ingen ouppklarad förändringsbegäran, ingen sammanslagningskonflikt, och ett rent granskat träd; sammanslagningen är squash-och-radera. main framsteg endast genom Port 2 staging → main pull request och bevarar härstamning med ett merge-commit. Direkt push till grenar är inte release-arbetsflödet.

Staging- och produktionsdistributioner utlöses från motsvarande skyddade staging och main branch-stater efter CI. Pull-request-kod och fork-uppgifter får inte deploy-hemligheter.

Hemligheter som används i deploy-arbetsflöden är avgränsade till deploy-miljön av vår CI-plattform. De är inte tillgängliga för pull-request-arbetsflöden från forks.


12. Koordinerat avslöjande

Om du tror att du har hittat en säkerhetssårbarhet i qub vill vi höra om det snabbt och vi förbinder oss att hantera rapporten professionellt.

Vi bekräftar mottagandet inom tre arbetsdagar och håller dig informerad medan vi utreder. Med ditt samtycke krediterar vi rapportörer i releasenoteringar.

12.1 Safe Harbor

Om din forskning följer reglerna ovan (god-trogen undersökning, ingen skada på andra användare eller tjänsten, rimligt avslöjandefönster), kommer vi inte att vidta rättsliga åtgärder mot dig, och vi kommer inte att be brottsbekämpning att göra det. Vi behandlar ditt arbete som auktoriserad testning och vi vill hellre att du hittar buggen än någon annan.

Detta Safe Harbor gäller:

Det gäller inte social manipulation av qub-teammedlemmar, denial-of-service-tester eller åtkomst till andra användares data utöver vad som behövs för att demonstrera problemet. Om du är osäker på om något faller inom Safe Harbor, fråga först med samma [SECURITY]-ämnesprefix.


13. Ärliga begränsningar

Säkerhet är en praktik, inte ett tillstånd. Vissa begränsningar är värda att namnge direkt:


14. Ändringar på denna sida

Materiella ändringar noteras genom att uppdatera ikraftträdandedatumet högst upp. Där en ändring återspeglar en konkret säkerhetsförbättring beskriver vi den kort i den offentliga changeloggen. Där en ändring återspeglar ett policyförtydligande beskriver vi vad som ändrats och varför.

För frågor om något på denna sida, mejla support@qub.social med ämnesprefixet [SECURITY].


15. Ändringslogg

Version Ikraftträdandedatum Sammanfattning
1.1 23 september 2026 Förenade kryptografiska påståenden, leveranssätt, lagring, CSP, sessioner, API-nycklar, betalningar, CI och release-arbetsflöde med det implementerade systemet.
1,0 2 maj 2026 Första publicering.