Statly / Juridik / Säkerhet

Kontrollerna, och vad de faktiskt gör

Det här är inte en förtroendesida med hänglåsikoner. Det är en genomgång av de kontroller som finns i koden, vad de skyddar mot, och var gränserna går. Sist på sidan står exakt hur långt vi kommit med SOC 2, vilket inte är hela vägen, och det säger vi hellre själva.

Senast uppdaterad 20 september 2026 Sårbarheter: security@frontness.se

Kort sagt

  • Den bästa säkerhetsåtgärden är att inte ha datan. Mätdatan innehåller inga personuppgifter. Ett intrång ger en angripare sidvisningsstatistik, inte människor.
  • Lösenord hashas med Argon2id. Sessionstoken lagras hashad, så en läckt databas ger ingen inloggning.
  • Allt som ändrar något kräver CSRF-kontroll. Inloggning och registrering är hastighetsbegränsade.
  • Varje åtgärd på ett konto skrivs till en oföränderlig revisionslogg som applikationen aldrig raderar ur.
  • SOC 2: kontrollerna finns och är byggda för att gå att revidera. Någon revision är ännu inte genomförd. Vi tar fram rapporten för företagskunder som behöver den.

01Utgångspunkten: mindre data att skydda

Ett analysverktyg är normalt ett av de mest känsliga systemen ett företag har: det vet vem som besökt vilka sidor, från vilken IP-adress, vid vilken tidpunkt. Läcker det systemet läcker människor.

Vår mätdata går inte att läcka på det sättet, för den innehåller inga personuppgifter. IP-adressen skrivs aldrig. User-agent-strängen skrivs aldrig. Besökaren är en hash vars ingredienser är utplånade efter två dygn. En angripare som stjäl hela databasen får veta att någon läste /priser från Borås på en tisdag, och inget mer.

Det som är värt att skydda är kontona: e-postadresser, lösenordshashar, sessioner och kundernas statistik. Resten av den här sidan handlar om det.

02Åtkomstkontroll

Minsta möjliga rättighet

Varje API-anrop utom mätpunkten börjar med en kontroll av att någon är inloggad. Varje anrop som rör en sajt kontrollerar dessutom att sajten faktiskt tillhör den inloggade.

Ett försök att läsa någon annans sajt svarar 404 Sidan finns inte, inte 403 Förbjudet. Skillnaden är inte kosmetisk: ett 403-svar bekräftar att domänen finns hos oss, och då går kundlistan att kartlägga genom att gissa domäner. Administratörsytan beter sig likadant: för den som inte är administratör existerar den inte.

Roller

  • user: ser sina egna sajter och sitt eget konto. Ingenting annat.
  • admin: drift och support. Har åtkomst till administratörsytan, och varje åtgärd där hamnar i revisionsloggen med namn och tidpunkt.

Vad en plan får göra avgörs på ett enda ställe i koden (plan_can()), inte genom att jämföra plannamn på tjugo ställen i gränssnittet. Behörighetsregler som ligger utspridda är behörighetsregler som till slut inte stämmer överens.

Fysisk och administrativ åtkomst

Databasfilen ligger utanför webbroten och kan inte hämtas över HTTP. Åtkomst till servern har den som driver tjänsten, i praktiken ett fåtal personer, med nyckelbaserad inloggning. Vi är ett litet bolag och låtsas inte ha en personalavdelning som återkallar behörigheter; vi har i stället få behörigheter att hålla reda på.

03Spårbarhet: revisionsloggen

SOC 2 vill kunna se vem som gjorde vad, när. Det gör tabellen audit_log. Den skrivs till av allt som betyder något: inloggning, misslyckad inloggning, lösenordsbyte, ny sajt, raderad sajt, planbyte, registerutdrag, kontoradering, körda cron-jobb, administratörens åtgärder.

Kolumnerna i audit_log
KolumnInnehåll
tsTidpunkt.
actorE-postadressen vid tillfället, eller system för schemalagda jobb.
actionlogin.ok, site.delete, plan.change, account.export
targetVad åtgärden gällde.
ip_prefixNätprefix, aldrig hela IP-adressen.
detailJSON med det som behövs för att förstå raden i efterhand.

Loggen är oföränderlig i den meningen att applikationen aldrig raderar ur den och aldrig skriver om en befintlig rad. Den har med flit ingen främmande nyckel mot users, för annars hade en kontoradering svept med sig historiken över raderingen. När du raderar ditt konto skrivs din e-postadress i loggen över med ”raderad användare”: att det hände står kvar, vem det var försvinner.

Du kan läsa din egen del av loggen. De 500 senaste raderna ingår i registerutdraget du hämtar i appen. Vi loggar inte i hemlighet.

04Lösenord och sessioner

Lösenord

  • Hashas med Argon2id: 64 MiB minne, 4 iterationer, 2 trådar. (Saknar värdens PHP Argon2 faller vi tillbaka på bcrypt med kostnad 12.)
  • Minst 12 tecken. Inga påtvingade specialtecken: längd slår teckenklasser, vilket är NIST:s rekommendation och inte en åsikt vi hittat på.
  • De uppenbart svaga lösenorden stoppas vid registreringen.
  • Vi har aldrig lösenordet i klartext på disk. Byter du lösenord loggas alla dina andra enheter ut automatiskt.

Sessioner

  • En session är 32 slumpade byte i en HttpOnly-kaka med Secure och SameSite=Lax.
  • I databasen ligger bara SHA-256-hashen av tokenen. En läckt databasdump ger alltså ingen giltig inloggning.
  • Livslängd: 30 dagar. Utgångna sessioner städas bort av nattjobbet.
  • I appen ser du dina aktiva enheter (”Chrome på macOS”, IP-prefix, senast sedd) och kan logga ut alla andra med en knapp.

Varför SameSite=Lax och inte Strict

Med Strict hade du varit utloggad varje gång du kommer tillbaka till oss från en annan sajt, till exempel från en inloggningslänk i mejlet. Lax plus CSRF-kontroll på allt som ändrar något ger samma skydd utan att gå sönder, och en kontroll som går sönder är en kontroll folk stänger av.

05Kryptering och transport

  • All trafik går över TLS. Spåraren, API:et, appen, de här sidorna. Kakorna sätts med Secure i produktion.
  • Utgående anrop (SendGrid, Google Search Console) sker över HTTPS med API-nycklar som ligger i en .env-fil utanför webbroten och aldrig i versionshanteringen.
  • Databasfilen ligger utanför webbroten på svensk disk, med filsystemets åtkomstkontroll som skydd.
  • Prepared statements överallt. Ingen SQL byggs av strängkonkatenering, i någon endpoint.

En sak vi inte påstår

Vi påstår inte att varje kolumn är krypterad i vila. Databasen är en SQLite-fil på en server vi styr över. Det som skyddar mätdatan är inte kryptering, utan att den inte innehåller några personuppgifter att kryptera. Lösenorden är hashade, sessionstoken är hashad, och det är där skyddet ligger. Behöver din organisation kryptering i vila på lagringsnivå är det en del av Företag-planen, där du får en egen instans. Fråga oss, så säger vi vad som faktiskt är på plats.

06CSRF och hastighetsbegränsning

CSRF

Varje anrop som ändrar något (POST, PATCH, DELETE) kräver att ett värde ur en kaka vi satt också skickas med som HTTP-huvud. En annan sajt kan få webbläsaren att skicka med kakan, men kan inte läsa den, och kan därför inte sätta huvudet. Saknas eller stämmer det inte: 419, och ingenting händer.

Hastighetsbegränsning

Vad som faktiskt är begränsat, och hur hårt:

Gränser per åtgärd
ÅtgärdGränsPer
Inloggning30 / 15 minnät (IP-prefix)
Inloggning8 / 15 mine-postadress
Registrering5 / timmenät
Glömt lösenord5 / timmenät
Byte av lösenord10 / timmekonto

Engångstokens för e-postverifiering och lösenordsåterställning lagras hashade, lever i en timme, kan användas en gång, och en ny token gör den gamla ogiltig. Funktionen ”glömt lösenord” svarar likadant oavsett om e-postadressen finns hos oss eller inte. Annars vore den ett verktyg för att ta reda på vilka som är kunder.

07Säkerhetskopior och drift

  • Dagliga säkerhetskopior av databasen. Kopiorna ligger på samma svenska infrastruktur som databasen och lämnar aldrig landet. En säkerhetskopia i ett amerikanskt moln hade gjort hela produktlöftet osant.
  • Databasen körs i WAL-läge, så att en läsning aldrig blockerar en skrivning och en avbruten skrivning inte lämnar filen trasig.
  • Återläsning provas. En säkerhetskopia som aldrig har lästs tillbaka är en förhoppning, inte en kopia.
  • Fel loggas, aldrig till besökaren. I produktion visas inga PHP-fel i svaret; de hamnar i serverns egen logg.
  • Inga externa beroenden. Projektet har medvetet ingen Composer och inga npm-paket. Ett bibliotek på 40 000 rader är en försörjningskedja vi inte vill ha i en tjänst som säljs på att data inte lämnar landet.

08Incidenthantering och 72 timmar

Upptäcker vi ett intrång eller en läcka gör vi följande, i den ordningen:

  1. Omedelbart

    Stoppa och bevara

    Vi stänger vägen in, river alla aktiva sessioner om det behövs, och rör inte revisionsloggen. Den är underlaget för utredningen.

  2. Inom 24 timmar

    Fastställ omfattningen

    Vad kom man åt? Vilka konton? Vilken data? Revisionsloggen och serverloggarna ska kunna svara på det. Det är därför de finns.

  3. Inom 72 timmar

    Underrätta

    Berörda kunder får besked inom 72 timmar från att vi upptäckt incidenten. Är personuppgifter vi ansvarar för inblandade anmäler vi till Integritetsskyddsmyndigheten inom samma frist, enligt artikel 33. Är det data där du är ansvarig och vi biträde underrättar vi dig utan onödigt dröjsmål, så att du hinner göra din anmälan.

  4. Efteråt

    Skriv ned vad som hände

    Du får veta vad som gick fel och vad vi ändrat, i klartext. Inte ”en säkerhetshändelse har inträffat hos en av våra leverantörer”.

Besked skickas till kontots e-postadress. Vi väntar inte tills utredningen är klar med att höra av oss. Ett tidigt och ofullständigt besked är mer värt för dig än ett sent och komplett.

09Ansvarsfull sårbarhetsrapportering

Hittar du ett säkerhetshål, hör av dig till security@frontness.se. Skriv vad du hittade och hur man återskapar det. Kryptering på begäran.

Vad du kan förvänta dig

  • Bekräftelse inom 72 timmar, av en människa.
  • En bedömning och en tidsplan inom en vecka.
  • Kredit i vår tacklista när hålet är lagat, om du vill ha det.
  • Vi vidtar inga rättsliga åtgärder mot dig, förutsatt att du håller dig till reglerna nedan.

Vad vi ber om

  • Testa mot ditt eget konto och dina egna sajter. Skapa ett gratis provkonto: det tar en minut och kostar ingenting.
  • Läs, ändra eller radera inte andras data. Kan du bevisa åtkomsten utan att ta datan, gör det.
  • Inga överbelastningsattacker, ingen spam, ingen social manipulation av oss eller våra leverantörer.
  • Ge oss rimlig tid att laga innan du publicerar.

Vi har ingen bug bounty och betalar ingen belöning. Det säger vi rakt ut i stället för att låta dig upptäcka det efteråt.

10Var vi faktiskt står med SOC 2

Vi har ingen genomförd SOC 2-revision. Ingen oberoende revisor har ännu uttalat sig om våra kontroller, och vi har ingen Type I- eller Type II-rapport att skicka i dag. Skulle vi skriva något annat vore det just den sortens påstående vi bygger hela produkten på att slippa göra.

Det vi har är kontrollerna, byggda för att kunna revideras:

SOC 2-kriterierna, och hur de ser ut hos oss
KriteriumSå här är det löstLäge
Logisk åtkomstRoller, ägarkontroll per sajt, 404 i stället för 403, allt bakom inloggning utom mätpunktenPå plats
AutentiseringArgon2id, minst 12 tecken, hashade sessionstoken, hastighetsbegränsningPå plats
Övervakning och spårbarhetOföränderlig audit_log, e-post och IP-prefix, aldrig raderad av applikationenPå plats
ÄndringshanteringMigrationer i kod, framåtriktade och versionsnumreradePå plats
Kryptering i transportTLS överallt, Secure/HttpOnly-kakor, nycklar utanför webbrotenPå plats
TillgänglighetDagliga säkerhetskopior, WAL, provad återläsningPå plats
IncidenthanteringProcess och 72-timmarsåtagande, enligt avsnitt 08På plats
Oberoende revisionRevisor, granskningsperiod och rapportInte genomförd

För företagskunder tar vi fram rapporten. Behöver din organisation en SOC 2-rapport, ett personuppgiftsbiträdesavtal eller svar på ett leverantörsformulär inför ett beslut: hör av dig, så gör vi det arbetet inom ramen för Företag-planen. Vi säger till när revisionen är genomförd genom att ändra den här sidan, inte genom att i förväg skriva att den är det.

Kontakt

Sårbarheter: security@frontness.se
Efterlevnad och leverantörsformulär: hej@frontness.se
Dataskyddsfrågor: petri@frontness.se
Life Flow AB (Statly), Borås, Sverige