Heatrail

Turvalisus

Turvalisus ja arhitektuur.

Kuidas Heatrail on ehitatud ja millised garantiid kehtivad rakenduse all. Iga kontroll sellel lehel nimetab mehhanismi, mis teda jõustab, nii et ülevaataja saab selle ise üle kontrollida.

Ülevaataja kokkuvõte

Ainult nõuandev, fail-open, range 800 ms eelarve. Toores e-post ja telefon ei jõua meieni kunagi. Ainult lisatav logiraamat öise Ed25519 ankru ja kontrolllõksuga. Ainult EL. Kontrollid on kaardistatud OWASP ASVS 2. taseme vastu.

01

Ohumudel

Mida me kaitseme, ja kelle vastu.

Heatrail hoiab kolme vara, mida tasub rünnata: jagatud võrgu räsitud identifikaatorid ja tuletatud kuumuse olek, selle olekut põhjendava ajaloo terviklus, ja kaudselt iga kassa kättesaadavus, mis meid kutsub. Kolmandat kaitseb disain, mitte tööaeg: me võtsime ära võime kassat üldse mõjutada.

Joonis 1

Üks piir teie poe ja Heatraili vahel, ja tema taga üks ELi piirkond.Vasakul on kast pealkirjaga Teie pood, mis ütleb, et toored väärtused elavad ainult seal. Paremale viib kaks teed. Ülemine on pidev nool sildiga räsid ja klassid. Alumine on katkendlik joon sildiga toored väärtused, mis peatub pideva tõkke ees enne piiri. Paremal on suur kast pealkirjaga Heatrail, AWS eu-central-1 Frankfurtis. Selle sees on kolm nooltega ühendatud kasti: API, Postgres, mis hoiab ainult teise astme väärtusi, ja võtmeväärtuse hoidla. Kasti all olevad märkused ütlevad, et teise astme võtit hoiab API protsess, et teda ei ole üheski varukoopias ja et andmed ei lahku sellest piirkonnast. Joone all nimetavad kaks loendit, mis piiri ületab, ehk esimese astme räsid, tellimuse IP-aadress, seadme klassid, tellimuse kontekst vahemikena ja tellimuse viide, ning mis piiri kunagi ei ületa, ehk toores e-post ja telefon, nimed, tarneaadressid, tellimuse read, täpsed summad ja kaardinumbrid.Üks piir. Kõik sellest paremal jookseb ühes ELi piirkonnas.Teie poodToored väärtusedelavad ainult siin.räsid ja klassidtoored väärtusedHeatrailAWS eu-central-1, FrankfurtAPIteise astme võtiPostgresainult h₂ väärtusedVõtmeväärtusehoidlaTeise astme võtit hoiab API protsess.Teda ei ole üheski varukoopias, ja andmed ei lahku sellest piirkonnast.Mis piiri ületabEsimese astme räsid, tellimuse IP-aadress, seadme klassid, tellimuse kontekst vahemikena, tellimuse viide.Mis piiri kunagi ei ületaToores e-post ja telefon, nimed, tarneaadressid, tellimuse read, täpsed summad, kaardinumbrid.
Üks piir otsustab, mida me üldse hoida saame. Kõik tema taga jookseb ühes ELi piirkonnas, ja teise astme võti jääb API protsessi.
Osalev pood, kes loeb võrku
Realistlik esimene rünne on seaduslik klient, kes kasutab API-t otsinguoraaklina: sondeerib identifikaatoreid, loeb skoori, rekonstrueerib teiste poodide pettuseandmeid. Vastu seisab nõue, et iga kontroll kannab päris session_ref või order_ref väärtust, vastamine kategooriates mitte tõendites, poe kaupa läbipaistmatud jäljealiased, ja võtme kaupa kiiruspiirang. Piiride kohal külmutatakse võti, mille liiklus lakkab kassa liikluse moodi olemast. Ainus hulgitee, üks ajaloo skann Pro poe kohta, kannab kirja pandud ülempiiri ja on kirjas lõigus oraakli barjäärid. Miks ankurdatud, ainult kategooriate vastus teeb võrgu sõelumatuks, mitte pelgalt tüütuks sõeluda, on kirjas lehel Miks võrku ei saa loetleda.
Osalev pood, kes mürgitab võrku
Eksinud või pahatahtlik kaupmees, kes sildistab konkurentide kliente pettuseks. Vastu seisavad sildi semantikad, kuumust tekitavad ainult fraud ja chargeback, real ei tekita midagi, üks aktiivne silt tellimuse kohta, ja nende kohal piir sellele, kuhu üks silt ulatub. Pettuse silt teeb ostja seadme ja IP-aadressi kuumaks kõigile Pro poodidele korraga. E-post ja telefon, mida igaüks saab kellegi teise nimel sisestada, saavad mujal täiskaalu alles siis, kui need on kinnitatud või seotud sama seadmega. Võrgutasand vajab kahte sõltumatut omanikku. Kõik need signaalid on nõuandvad ega peata kunagi ostu. Mida kinnitus nõuab, ja miks sõltumatus on omandi omadus, mitte kontode oma, on kirjas lehel Kinnitus.
Ründaja, kellel on meie andmebaas
Vastu seisab see, et me ei saa kunagi andmeid, mida tasuks varastada. Kontaktandmed jõuavad kohale juba räsituna ja räsitakse uuesti materjaliga, mis elab andmebaasist väljas. API volitused hoitakse AES-256-GCM krüpteerituna võtmega, mis ei ole raamistikuvõti, ja kaardiandmeid siin ei ole üldse.
Ründaja, kellel on operaatori konto
Vastu seisavad TOTP, IP-ga seotud sessioonid, uus väljakutse tundlike toimingute juures ja auditirida iga lugemise kohta. Tuvastusreeglid on API-st teadlikult kättesaamatud: täielik operaatori ülevõtmine ei saa ikkagi muuta, kuidas kedagi skooritakse.
Meie ise, kes vaikselt ajalugu muudab
See, mida kõrvaline ei saa kontrollida sellega, et usaldab meid rohkem. Vastu seisavad ainult lisatav räsiahel, öine Ed25519 allkiri selle pea peale, ja öine käik, mis neid kahte võrdleb. Peatükk 07 nimetab kolm kihti ja selle, mida igaüks neist jõustab.
Heatrail on aeglane või maas
Käsitletud ohuna poele, mitte meile. Vastatud struktuuriga: klient loobub 800 ms juures ja tellimus läheb edasi. Kättesaadavus ei ole meie mudelis konfidentsiaalsuse ega tervikluse kontroll.
02

Võimetused

Mida Heatrail teha ei saa.

Igaüks neist on võimekus, mille me eemaldasime, mitte poliitika, mida lubame järgida. Eemaldatud võimekust ei saa seadistusveaga tagasi tuua.

  • Ta ei saa ostu blokeerida, viivitada, tühistada ega kinni hoida. Vastus on andmed, mida teie kood võib kasutada või ignoreerida. Tagasikutset ei ole, veebihaaki, mis makset väravaks teeks, ei ole, ja seadistust, mis muudaks nõuandeva jõustavaks, ei ole.
  • Ta ei saa vastu võtta ostja nime, tarneaadressi, toorest e-posti aadressi, toorest telefoninumbrit, tellimuse ridu ega kaardinumbrit. Tundmatud väljad lükatakse tagasi, neid ei ignoreerita.
    See väide käib ostja kohta, ja üks väli jääb sellest välja. Kui pood paneb sildi, saadab ta labelled_by, vaba teksti kuni 128 prinditava märgiga, mis nimetab, kes poes otsuse tegi, ja pood võib sinna panna töötaja e-posti aadressi. See on poe personali andmed, mitte ostja andmed. Püsiv ahel hoiab ainult läbipaistmatut tegutseja viidet, ja loetav väärtus elab eraldi pärinemiskirjes oma 90 päeva aknaga. Kuhu ta läheb ja kui kaua ta jääb, on välihaaval kirjas API viites.
  • Ta ei saa näidata ühele poele teise poe tellimust, intsidenti ega tõendit. Päring teise poe ressursi kohta saab vastuse, nagu seda ei oleks olemas.
  • Tema skoorireegleid ei saa API kaudu muuta. Reeglite otspunkt on konstruktsiooni järgi ainult loetav. Reeglimuudatused lähevad koodideploy'ga ja kirjutavad logiraamatu sündmuse.
  • Ta ei saa ise saata raportit politseile, CERT-ile ega partnerile. Organite memo on mustand, mille inimene vaatab üle ja saadab.
  • Ta ei saa oma ajalugu ümber kirjutada. Rollil, millega rakendus ühendub, on logiraamatul INSERT ja SELECT ja mitte midagi muud, ja peatükk 07 laotab selle kiht kihi haaval lahti.
03

Kättesaadavus

Fail-open, ja harjutus, mis seda tõestab.

Lisa ja SDK jõustavad range 800 ms eelarve. Selle möödudes klient loobub päringust, märgib kontrolli degraded, paneb koormise kohalikku kordusjärjekorda ja tagastab juhtimise teie kassale. SDK keeldub nullväärtusega ajalimiidist konstrueerimisel, sest aluseks olev HTTP klient loeb nulli kui ajalimiiti ei ole üldse. See võidaks eelarve vaikselt, seega see lükatakse tagasi, mitte ei võeta vastu.

Sildistamine käitub teadlikult vastupidi. Kontroll ei tohi kunagi visata, aga silt ei tohi kunagi vaikselt kaduda, seega ta tõstab vea, mida teie järjekord saab korrata.

kontrolli esimesel tööpäeval produktsioonis, 1. september 2026
78
mediaan ringkäik, mõõdetud üle selle päeva
386 ms
95. protsentiil, range 800 ms eelarve vastu
610 ms
stagingu harjutus: kassa lõpuni, kui Heatrail on teadlikult kättesaamatu
16 ms

Katkestusharjutus tehti stagingus samal päeval: Heatraili hosti DNS lahendus murtud teadlikult, ost läks lõpuni, kontroll tagastas degraded 16 ms-ga, ja järjekorras olev koormis tühjenes, kui teenus naasis. Kolm latentsusarvu on produktsioonimõõtmised.

04

Päringu autentimine

HR1: allkirjastatud päringud, ühekordsed nonce'd, oraakleid vigades ei ole.

Iga poe päring on allkirjastatud. Kandjatunnust, mis kordub igavesti, ei ole, ja API võtit päringureas ei ole.

Allkiri
Iga päring allkirjastatakse poe kaupa volitusega, üle meetodi, tee, aja, ühekordse nonce'i ja keha. Kanooniline kuju on üks jagatud teostus, mida kasutavad nii SDK kui API, mitte kunagi kaks, ja mõlemad testikomplektid kinnitavad sama jagatud testvektorite hulka, seega klient ja server ei saa lahkneda selles, mis allkirjastati. See on dokumenteeritud rida realt, koos läbitöötatud vektoriga, mida saate korrata, lehel API viide.
Korduskaitse
Päring võetakse vastu ainult lühikeses aknas serveriaja ümber, ja iga nonce võetakse vastu korra. Sama nonce'i teine esitamine keelatakse. Aken ja kui kaua nonce't mäletatakse on liidestuslepingu osa, mitte saladus, ja API viide ütleb mõlemad.
On kolmas reegel, mille enamik teostusi jätab kahe silma vahele: pärast nonce hoidla taaskäivitust on tema ajalugu kadunud, seega päring, mis on tembeldatud enne seda taaskäivitust, võiks olla kordus, mida me enam ei tuvasta. Täpselt need lükatakse tagasi. Praeguse aja päringud lähevad läbi.
Autentimisoraaklit ei ole
Iga tõrge, vigane päis, tundmatu võti, halb allkiri, nihkes kell, vale ulatus, tagastab sama üldise 401. Tundmatu võti põletab ikkagi ühe HMAC-i näivväärtuse vastu, et mõlemad teed maksaksid sama töö, ja võrdlus ise on konstantse ajaga. Eraldi vastus „ebapiisav ulatus“ kinnitaks, et allkiri kontrollis, seega me seda ei anna.
Ulatused, vahetus, külmutus
Võtmed kannavad check või label ulatust. Vahetus on kattuv: pensionile läinud võti hoiab armuaega aegumise ajatempli kaudu ja tühistatakse jäädavalt tunnise tööga, kui see tähtaeg möödub. Ülevaatamiseks külmutatud võti on ainus teadlik erand üldisest 401-st, ta vastab 403 key_frozen, ja ainult pärast allkirja kontrollimist.
Kiiruspiirang
Võtme kaupa, paisepiir ja püsipiir, mõlemad aatomloendurid, ja tagasilükatud päring loeb nende sisse täpselt nagu vastuvõetud, seega kutsuja ei saa sondeerida kiiremini sellega, et on vale. Piirid on avaldatud API viites, sest liidestaja peab nende vastu ehitama. Piiride kohal külmutatakse ülevaatuseks võti, mille liiklus lakkab kassa liikluse moodi olemast.
Idempotentsus
Iga POST nõuab Idempotency-Key päist. Nõue on püsiv, mitte puhverdatud, ja ta võetakse enne iga kõrvalmõju jooksmist, seega garantii elab puhvrikaotuse üle. Kordus sama kehaga kordab salvestatud vastust ja teine keha sama võtme all on 409. Serveriviga vabastab nõude, seega kordus jookseb päriselt uuesti, mitte ei jää lukku tõrke taha, millel ei olnud kunagi mõju. Kui kaua nõuet hoitakse, ja veakoodid iga juhtumi kohta, on API viites.
05

Räsimise piir

Kaks etappi, kaks võtit, kaks masinat.

Joonis 2

Kaks astet kahes masinas. Pood võtmestab kontaktväärtuse korra, Heatrail võtmestab tulemuse uuesti, ja salvestatakse ainult teine väärtus.Vasakul on kast pealkirjaga Teie pood. Selle sees on väli kliendi e-posti aadressiga, nool märkega HMAC jagatud võrgusoola all, ja teine väli esimese räsiväärtusega, mis on kirjas kujul h üks. Kasti sees olevad märkused ütlevad, et toores väärtus jääb sellesse masinasse ja et teie serverist lahkub ainult h üks. Üks pidev nool ületab vahe paremale ja kannab silti, et piiri ületab ainult h üks. Paremal on kast pealkirjaga Heatraili API, kuhu h üks saabub. Nool märkega argon2id, kaksteist mebibaiti mälu iga katse kohta viib teise ja teistsuguse räsiväärtuseni, mis on kirjas kujul h kaks. Märkused ütlevad, et serveri võti ei lahku sellest masinast ja et andmebaasi kirjutatakse ainult h kaks. Kastide all lahkub katkendlik joon kliendi aadressi juurest, jookseb paremale ja peatub pideva tõkke ees enne piiri. Tema silt ütleb, et toores väärtus ei liigu kunagi seda teed. Lõpurida ütleb, et salvestatakse ainult teine väärtus, seega andmebaasi koopia ei ole see hulk väärtusi, mille teie pood arvutas.Esimene aste, teie poesTeine aste, Heatraili API-sTeie poodHMAC jagatud võrgusoola allmari.tamm@example.eeh₁ 9f3a…Toores väärtus jääb sellesse masinasse.Teie serverist lahkub ainult h₁.liigub ainult h₁Heatraili APIargon2id, 12 MiB iga katse kohtah₁ 9f3a…h₂ c4f1…Serveri võti ei lahku sellest masinast.Andmebaasi kirjutatakse ainult h₂.toores väärtus ei liigu kunagi seda teedSalvestatakse ainult teine väärtus, seega andmebaasi koopia ei ole see hulk väärtusi, mille teie pood arvutas.
Väärtus, mille teie pood saadab, ei ole aadress, ja väärtus, mille meie salvestame, ei ole see, mille teie pood saatis.
  1. Esimene etapp jookseb teie poes

    Teie server normaliseerib e-posti aadressi või telefoninumbri ja tuletab sellest võtmestatud väärtuse, materjali all, mis on jagatud osalevate poodide vahel. See tuletatud väärtus on see, mis meieni liigub. Toores väärtus ei lahku kunagi teie taristust, seega ei ole meie poolel seadistusviga, mis saaks panna meid seda vastu võtma.

  2. Teine etapp jookseb ainult Heatraili API-s

    Me tuletame teise väärtuse, materjali all, mis ei ole kunagi olnud mujal kui selles serveris, enne kui midagi salvestatakse. Ainult see teine väärtus kirjutatakse kunagi, seega meie andmebaasi väärtused ei ole need, mille te arvutasite, ja andmebaasi koopia ilma selle materjalita ei saa joonduda sellega, mida te saadate.

  3. Rollid on teadlikult lahku löödud

    Kolm rolli, kolm võtmematerjali, ülekoormust ei ole: jagatud materjal on see, mis laseb kahel poel tunda sama identifikaatorit teineteisena, teine materjal ei lahku kunagi API serverist, ja volitus, millega te päringuid allkirjastate, ei mängi identifikaatorite räsimises üldse kaasa. Konstruktsioonid ise, väljade vormingud ja see, mida te tegelikult teostate, on dokumenteeritud seal, kus te neid vajate, SDK viites ja API viites. Sellel lehel on omadus, mis jääb tõeseks ükskõik kuidas mehhanism ehitatakse.

  4. Tühjad ja kohatäite väärtused keelatakse, neid ei räsi

    Tühja stringi või poe kohatäite aadressi räsi saaks üheks tohutuks sõlmeks, mis seob iga külaliskassa võrgus. Räsifunktsioon keeldub tühjast sisendist otsekohe ja tagastab kohatäite puhul tühja. Leping on, et väli jäetakse siis päringust täielikult välja, ja API lükkab lisaks saabumisel tagasi tuntud kohatäite räsib.

Räsitud andmed on endiselt isikuandmed

Räsitud e-posti aadress on GDPR-i järgi isikuandmed, ja Heatrail töötleb seda vastavalt. Jagatud võrgusool asub iga osaleva poe serveris, sest sama inimese äratundmine eri poodides nõuab, et iga pood arvutaks sama väärtuse. Leht Identiteet ilma isikuteta selgitab, kuidas see disain toorest väärtust kaitseb.

Teisel etapil on töötegur, ja siin on, mida ta annab

Esimene etapp on endiselt üks võtmestatud räsi, mis arvutatakse poes. Teine etapp, mida arvutab ainult meie server, on tahtlikult aeglane ja mälumahukas tuletus: argon2id, 12 MiB mälu iga katse kohta. Kirje kaupa soola endiselt ei ole, sest sama inimese äratundmine eri poodides nõuab, et iga poe väärtus klapiks. Seega keegi, kellel on andmebaasi koopia ja mõlemad võtmematerjalid korraga, saab kandidaatväärtusi endiselt proovida, aga iga katse maksab nüüd umbes 13 ms ja 12 MiB ühel tuumal. Mõõdetult on realistlik kümne miljoni Eesti mobiilinumeratsiooni ruum umbes 37 tundi ja kogu kaheksakohaline ruum umbes 15 päeva. Enne võtsid samad otsingud 52 s ja üheksa minutit.

Number ilma tingimusteta on vale number, seega: üks tuum Apple M1 Pro peal, PHP 8.4 käsurealt, libsodium 1.0.20. Rohkem tuumi jagab need ajad, ja selleks ehitatud riistvara teeb veel paremini. Lühikest sihtnimekirja see ei kaitse. Sada numbrit võtab umbes poolteist sekundit. Ja enne muudatust kirjutatud read kannavad vana kiiret räsi, kuni tavaline säilitus nad eemaldab. See on 90 päeva, või kauem, kui rida on tõend lahtises pettusejuhtumis.

06

Minimeerimine

Lubatud nimekiri, ja barjäärid, mis takistavad tal oraakliks saamast.

Mida API vastu võtab

  • E-posti ja telefoni esimese etapi räsib, ja valikuline püsiv pseudonüüm.
  • IP-aadress, kust tellimus tuli, kanooniliseks tehtud enne salvestust.
  • Tellimuse kontekst ainult klasside ja vahemikena: toote riskiklass, kogus, summa vahemik, konto vanuse klass, suunamise allika klass.
  • Tellimuse viide ja sessiooni pseudonüüm, vähemalt üks on kohustuslik.
  • Valikulised seadme omadused, lülitatavad poe kaupa: ekraani geomeetria, pikslisuhe, tuumade ja mälu klass, puutetundlikkus, ajavöönd, keelte nimekiri, platvorm, kasutajaagendi klass, ning canvas ja WebGL räsib. Lugege neid sellena, mis nad on: seadme konfiguratsioon ei ole seade, ja seade ei ole inimene. Tuhanded tehaseseadetes käed jagavad üht konfiguratsiooni, ja päris seadme taga võib olla kasutatud telefon, pere või operaatori aadress, mida jagab linn. Seepärast ei tõsta seadme sarnasus üksi kunagi hoiatust.

Mida ta keeldub

  • Nimed, tarneaadressid, toored e-posti või telefoni väärtused.
  • Kaardinumbrid või ükskõik milline maksevolitus.
  • Tellimuse read, ostukorvi sisu, täpsed summad.
  • Toored kasutajaagendi stringid seadme objektis.
  • Iga väli, mida nimekirjas ei ole, tundmatud võtmed ülatasemel, seadme objektis või tellimuse kontekstis on valideerimisviga, seega heade kavatsustega liidestus ei saa hakata andmeid sisse smuugeldama välja lisamisega.

Oraakli barjäärid

Kontroll peab olema ankurdatud päris kassasse: ilma sessiooni või tellimuse viiteta päring lükatakse tagasi ja midagi ei salvestata. Vastused kannavad kategooriaid, mitte kirjeid, ja tasub öelda täpselt, mida see lubab. Põhjuserea võib nimetada vaste liiki, mitut poodi vaste hõlmab, ja kui kaua aega tagasi, jämedates ühikutes. Ta ei kanna identifikaatorit, räsi, teise poe tõendit ega poe identiteeti. Seega avaldatud rida nagu 2 shop(s) affected ütleb teile, et vaste on kinnitatud kusagil mujal võrgus, ja ei nimeta kedagi: poodi, keda otsida, ei ole, ja kirjet, mille vastu teda lahendada, ei ole. Arv on kategooria. Täpne vastuse kuju on API viites. Jäljealiased on poe kaupa läbipaistmatud, seega sama jälg ilmub igale poele teise identifikaatori all ja teda ei saa kasutada stabiilse sangana võrgu sondeerimiseks. Valideerimisteated nimetavad rikkuvat välja ja ei kaja kunagi esitatud väärtust.

Ristpoodide päringud vastavad 404, mitte kunagi 403

Teise poe tellimuse, intsidendi, jälje või memo küsimine tagastab 404 not_found, sama vastuse kui millegi küsimine, mida ei ole olemas. 403 tähendab see on olemas ja te ei tohi seda saada, ja see üks bitt piisab loetlemiseks: pood võiks kõndida tellimuse viidete ruumis ja õppida, millised on päris kusagil mujal võrgus, kes kellele müüb, mis mahus, milliste identifikaatorite all. 404 annab ründajale sama vastuse „sellist tellimust ei ole“ ja „see ei ole teie tellimus“ kohta, seega sondeerimine ei tagasta midagi. Sama ühetaolisus kehtib sisemisel liidesel, mida partneriportaal kasutab, kus nimekirjast väljas kutsuja, omandi lahknemine ja tundmatu identifikaator annavad kõik ühe eristamatu 404. Selle ühe biti äravõtmine on rohkem väärt kui täpsem veateade liidestajale, kes kirjutas vale viite.

Üks hulgiotspunkt on olemas, ja see on erand, mille me teadlikult aktsepteerime, mitte möödalaskmine. Pro pood saab oma elu jooksul teha ühe ajaloo skanni, POST /v1/history-scan/sessions kaudu: üks seanss, mis on seitse päeva avatud, kokku kuni 250 000 minevikutellimust ja päringus kuni 100. Iga rida kannab tellimuse aega ja vähemalt üht kolmest: räsitud e-post, räsitud telefon, IP-aadress. Iga rida saab vastuseks strong, weak või none ainult kategooriates: milline väli vastas, kas teises poes või võrgutasandil, jäme poodide arv ja vanus, mitte kunagi identifikaatorit ega poe nime. Ühtegi rida alles ei hoita. Read ei ole ankurdatud kassasse, mida me nägime, seega selle ühe seansi kohta ülal toodud ankrureegel ei kehti, ja 250 000 rida on kirja pandud ülempiir sellele, mida poena esinev pettur sealt teada saab. Teise skanni jaoks peame poe lähtestama, ja põhjus läheb meie auditilogisse.

07

Terviklus

Ainult lisatav ajalugu, kolmes kihis.

Iga oluline sündmus, kontrollid mis loesid, sildid, operaatori toimingud, skooriseadistuse muudatused, lisatakse räsiahelaga logiraamatusse. Iga rida hoiab oma kanoonilise koormise SHA-256 ja reale räsi üle seq, sündmuse tüübi, koormise räsi ja eelmise rea räsi, alustades geneesi väärtusest kuuekümne nelja nulliga. Lisamised serialiseeritakse andmebaasi nõuandva lukuga, seega järjekorranumbrid on konstruktsiooni järgi pidevad ja väljaspool rada sisestamine murrab ahela, teadlikult, sest see murre on lõks. Milleks ajalugu on, ja miks organite tehniline toimik on siis minutite, mitte nädalate küsimus, on Tõend minutitega.

Joonis 3

Ainult lisatav ahel, öine allkiri tema pea peale väljaspool andmebaasi, ja öine käik, mis neid kahte võrdleb.Vasakul on kast pealkirjaga Logiraamat Postgresis, märkega ainult INSERT ja SELECT. Selle sees on neli reakasti järjekorranumbritega üheksateist kuni kakskümmend kaks, ja igaüks kannab eelmise rea räsi. Kolmas rida on esile tõstetud ja märgitud muudetuks. Temast lahkuv nool on kahe kriipsuga läbi kriipsutatud ja kannab silti ahel katkeb, sest järgmise rea salvestatud räsi enam ei klapi. Paremal, sellest kastist väljaspool, on kast pealkirjaga Öine ankur, milles on Ed25519 allkiri kuupäeva, järjekorranumbri ja rea räsi peale, võetud viis minutit pärast keskööd UTC järgi ja hoitud andmebaasist väljas. All on lai kast öise kontrolliga veerand tundi pärast keskööd UTC järgi. Ta ütleb, et ahel arvutatakse geneesist uuesti ja iga rida võrreldakse tema salvestatud räsidega, ja et päeva pead kontrollitakse operaatori seadistatud avaliku võtme vastu, mitte ankru kõrval oleva võtme vastu. Lõpurida ütleb, et muudetud rida raporteeritakse esimese lahknenud järjekorranumbri juures ja käsk väljub mittenulliga.Üks ahel, üks öine allkiri tema pea peale, üks öine käik, mis neid võrdleb.Logiraamat Postgresisainult INSERT ja SELECTseq 19eelmise räsiseq 20eelmise räsiseq 21muudetudahel katkebseq 22eelmise räsiÖine ankurdate:seq:row_hashEd25519 allkiri kell00:05 UTC, hoitakseandmebaasist väljas.Öine kontroll, 00:15 UTCArvuta ahel geneesist uuesti ja võrdle iga rida tema salvestatud räside vastu.Kontrolli päeva pead operaatori seadistatud avaliku võtme vastu, mitte ankru kõrval oleva võtme vastu.Muudetud rida raporteeritakse esimese lahknenud järjekorranumbri juures, ja käsk väljub mittenulliga.
Ühe rea muutmine murrab ahela järgmise juures, ja allkiri, mis päeva pead tõestab, elab väljaspool andmebaasi, mida ta kirjeldab.
Kiht 1, ahela käik
Öine käsk arvutab ahela geneesist uuesti ja võrdleb iga rida tema salvestatud räsida vastu. Üks pööratud bait, kustutatud rida või sisestatud rida raporteeritakse esimese lahknenud järjekorranumbri juures, ja käsk väljub mittenulliga.
Kiht 2, allkirjastatud ankur
Ahela käik üksi ei saa eristada päris ahelat sellest, mis räsitakse tervikuna edasi. Seega kell 00:05 UTC ankurdatakse päeva pea Ed25519 allkirjaga üle date:seq:row_hash, ja kontroll kell 00:15 UTC kontrollib seda allkirja operaatori seadistatud avaliku võtme vastu, mitte võtme vastu, mis elab ankru kõrval. Ümberkirjutatud ankru uuesti allkirjastamine ründaja võtmega seega ei lähe läbi. Produktsioonis on allkirjastamisvõti kohustuslik: käsk keeldub jooksmast, selle asemel et allkirjastada ühekordse võtmega.
Puuduvat ankrut ei kohelda ka vaikselt tervena. Kui vanim logiraamatu rida on vanem kui täis ankrutsükkel, on ankru puudumine ise tõrge, muidu oleks ankrute kustutamine odavaim viis ankru kaitset võita.
Kiht 3, andmebaasi load
Privileegideta tööaja rollil on UPDATE, DELETE ja TRUNCATE logiraamatul, auditilogil ja ankrute tabelil ära võetud, alles on ainult INSERT ja SELECT. Logiraamatu järjekorda ei saa ka liigutada. See on see, mis muudab „meie kood seda ei tee“ väiteks „andmebaas keeldub“.
Jõus produktsioonis alates 2. septembrist 2026, ja kontrollitud nii, nagu see leht eelistab: ühendudes selle rollina ja proovides keelatud kirjutusi. UPDATE logiraamatul, DELETE auditilogil, permission denied, andmebaasilt endalt.
Ja selle väite piir, öeldud siin täies mahus. Need tühistamised seovad rolli, millega rakendus tööajal ühendub. Nad ei seo eraldi omaniku volitust, mida hostimisplatvorm hoiab skeemimuudatuste jaoks. Me hoiame teda päringuid teenindavatest protsessidest eemal. Kõige vastu, mis selle volituseni jõuab, toetub ahel tuvastusele, mitte ennetusele: räsiahel, öised allkirjastatud ankrud, ja ahela pikkuse kirje, mida hoitakse andmebaasist väljas. Seega logiraamat, mis on tühjendatud või ankrutest lahti haagitud, ei saa esitleda end noorena, mida keegi ei ole veel ankurdanud. Andmetöötluslepingu lõige 5(3), mille te aktsepteeriksite, kannab sama piiri: ta dateerib lülituse, ütleb, et õigused seovad käitusaja rolli ja rakendust, aga mitte platvormi hoitavat omaniku volitust, ja et selle volituse vastu toetub ahel tuvastusele. Lugege neid kahte kõrvuti, sest see võrdlus on kontroll.

Logiraamat terve: 3 kannet kontrollitud allkirjastatud ankru vastu.

Ajastatud kontroll, produktsioon, 1. september 2026.

Logiraamat ja auditilogi on ka kaks tabelit, mida säilituse puhastus kunagi ei puutu, nad kannavad ainult identifikaatoreid, räsiprefikseid ja sündmuse metaandmeid, seega tõend jääb, samal ajal kui isikuandmed, millele ta viitas, kustutatakse ajakava järgi.

Mis tõstatab küsimuse, kes seda tegi, sest kanne, mis ei oska tegutsejat nimetada, ei ole kuigi palju auditijälg. Iga kanne kannab pärinemist, lõhestatud sama joone pealt. Püsiv ahel kirjutab läbipaistmatu tegutseja viite. Loetav pool, operaatori aadress või labelled_by väärtus, mille pood saatis, elab eraldi pärinemiskirjes oma 90 päeva aknaga ja kustutatakse sama öise puhastusega. Seega kes tegi on vastatav seni, kuni see loeb, ja pärast kadunud, ja ahel kontrollib ikkagi ilma selleta. Läbipaistmatu viide on varjunimeline, mitte anonüümne, ja me hoiame teda samadel artikli 17(3) alustel kui ülejäänud tõendit.

08

Operaatori konsool

Konsool on kõrgeima väärtusega sihtmärk, ja teda koheldakse nii.

TOTP, alati
Kehtiv parool avab sessiooni, mis ei jõua kuhugi mujale kui TOTP otspunktideni, kuni väljakutse läheb läbi. Kasutatud TOTP koodi ei saa esitada teist korda tema enda kehtivusakna sees.
IP-ga seotud sessioonid
Kanooniline sisselogimise aadress on sessiooni külge kinnitatud. Päring teiselt aadressilt ei saa lihtsalt keeldumist. Sessioon tühistatakse, sest seotud sessiooni nägemine mujalt koheldakse varastatuna.
Lisakinnitus tundlike toimingute juures
Jälje jahutamine ja usaldatud IP hulga muutmine nõuavad värsket TOTP väljakutset viimase 15 minuti jooksul, sõltumata sellest, kuidas sessioon avati. Usaldatud aadressiga sisselogimine jätab vahele ainult sisselogimise küsimuse, mitte kunagi lisakinnitust.
Iga lugemine auditeeritakse
Iga autenditud konsooli lugemine kirjutab auditirea samasse ainult lisatavasse tabelisse kui kirjutused, salvestades tegutseja, toimingu ja adresseeritud ressursi, mitte kunagi vastuse andmeid, räsib ega identifikaatoreid, mida ta tagastas.
Reeglid on API-st kättesaamatud
Skooriseadistuse kirjutamise otspunkti ei ole. Ta on versioneeritud repositooriumis ja läheb koodideploy'ga, iga muudatus kirjutab logiraamatu sündmuse. Täielik operaatori konto ülevõtmine ei saa ikkagi tuvastust muuta.
09

Võtmematerjal

Kuidas volitusi ja võtmeid hoitakse.

Poe API volitused
Genereeritakse võtme identifikaator pluss 32 juhuslikku baiti, näidatakse poele täpselt korra, ja hoitakse ainult AES-256-GCM šifritekstina värske juhusliku nonce'i ja autentimissildiga kirje kohta. Dekrüpteerimine tõrkub kinni iga rikkumise peale.
Eraldi raamistikuvõtmest
Hoidla võti on oma keskkonnaväärtus, teadlikult mitte rakenduse võti, mis kaitseb sessioone ja küpsiseid. Raamistikuvõtme vahetamine ei tohi kunagi murda iga poe API volitust.
Tõrku kiiresti, mitte kunagi pooleldi seadistatuna
Puuduv või vale pikkusega hoidla võti, räsimise materjal alla miinimumi, või puuduv ankru allkirjastamisvõti produktsioonis peatavad igaüks protsessi, selle asemel et vaikselt nõrgemasse režiimi langeda.
Ei logitakse kunagi
Võtmematerjal on märgitud tundlikuks parameetri tasemel, et ta redigeeritaks virnajälgedest. Allkirju ja võtmeväärtusi ei logita. Dekrüpteerimise tõrge logib ainult avaliku võtme identifikaatori.
Kaardiandmed
Ei puutu Heatraili kunagi. Makseandmed elavad ainult Stripe Checkoutis ja Billing Portalis, kuhu partneriportaal suunab.
10

Taristu

Üks piirkond, üks platvorm, andmed EList välja ei lähe.

Hostimine
Laravel Cloud AWS peal, piirkond eu-central-1 (Frankfurt). Rakendus, Postgres andmebaas, võtmeväärtuse hoidla ja järjekorra töötajad jooksevad kõik selles piirkonnas. Laravel Cloud ja AWS on meie ainsad alltöötlejad.
Varukoopiad
Seitse päeva säilitust koos taastamisega suvalise ajahetke peale, hoitud samas piirkonnas, kus on andmebaas, mida nad kaitsevad.
Transport
Ainult HTTPS. HSTS läheb iga turvalise vastusega, koos X-Content-Type-Options: nosniff, X-Frame-Options: DENY ja Referrer-Policy: no-referrer.
Sisu turvapoliitika
JSON API ei pea midagi laadima, seega JSON vastused kannavad default-src 'none'. HTML vastused saavad karastatud dokumendi poliitika ilma skriptita ja frame-ancestors 'none'. Poliitika järgib serveeritavat dokumenti, mitte hostinime, mille kaudu temani jõuti, vahe, mis oli päris leid meie enda ülevaatuses, mitte hüpoteetiline.
Ajastatud töö
Logiraamatu ankur 00:05 UTC, logiraamatu kontroll 00:15 UTC, säilituse puhastus 03:30 UTC, kaupmehe meeldetuletused 09:00 UTC, aegunud võtmete tühistamine iga tund.
11

Hoiak

Kontrollid on kaardistatud OWASP ASVS 2. taseme vastu.

Selle lehe kontrollid on kaardistatud kirje kaupa OWASP ASVS 2. taseme nummerdatud punktide vastu. Iga kirje nimetab faili, mis kontrolli teostab, ja testi, mis seda tõestab, ja dokument eristab selle, mida ülevaataja saab väljast kontrollida, sellest, mis vajab ligipääsu platvormile.

Kaardistus uueneb koos koodiga, ja kontroll loetakse kehtivaks siis, kui ta peab produktsioonis, mitte repositooriumis. Seepärast hinnatakse andmebaasi õiguste kihti peatükis 07 selle rolli järgi, millega rakendus päriselt ühendub.

Saatke kiri hello@heatrail.eu ja me jagame praegust versiooni teie turvameeskonnaga.

12

Avalikustamine

Haavatavusest teatamine.

Teatage aadressil security@heatrail.eu. Me tervitame kooskõlastatud avalikustamist ja ei jälita heas usus turvauuringut. Andke palun mõistlik aken enne avaldamist, ja palun ärge jookske teste, mis halvendaksid poe kassat. See on üks asi, mille kaitsmiseks see toode olemas on.

Meie masinloetav kord on sellel saidil aadressil /.well-known/security.txt ja vastab RFC 9116-le: Contact, Policy, mis osutab tagasi sellele peatükile, Canonical URI ja Expires kuupäev, mida RFC nõuab ja mis on väli, mis enamikul avaldatud kordadest puudub. Ta genereeritakse samadest ehituse aegsetest konstantidest kui ülejäänud sait, seega ta ei saa lahkneda aadressist, mida see leht teile näitab.

security@heatrail.eu on elus ja jälgitud, ja teade jõuab inimeseni, mitte järjekorda. Me nimetame teatajaid, kes tahavad olla nimetatud.

Hanke küsimustel on oma leht.

Heatrail

This site is not public yet

Heatrail is in a private pre-launch period. Enter the access password to continue.

Enquiries: hello@heatrail.eu