Sikkerhet og Robusthet

Et profesjonelt Norscode-produkt må fungere sikkert fra første versjon. Dette kapittelet gir et praktisk rammeverk du kan følge direkte i egne prosjekter.

Sikkerhet er sjelden ett enkelt tiltak. Det er summen av mange små og konsekvente valg: hva som valideres, hva som avvises, hva som logges, hvem som får tilgang, hvordan feil blir vist, og hvordan hemmeligheter håndteres. Når disse delene henger sammen, blir systemet mye vanskeligere å misbruke og mye lettere å drifte trygt.

Hvordan tenke om sikkerhet

Det viktigste prinsippet er å redusere tillit. Ikke stol på input utenfra, ikke stol på at klienten oppfører seg pent, ikke stol på at integrasjoner alltid sender riktig format, og ikke stol på at en bruker bare fordi de er innlogget også skal ha tilgang til alt. God sikkerhet bygges ved å kontrollere overganger mellom lag og ved å gjøre antagelser eksplisitte.

Det betyr også at sikkerhet ikke bør være et separat lag “på siden”. Inputvalidering, autentisering, autorisasjon, logging, deploy og drift er alle sikkerhetsflater. Når de behandles samlet, blir løsningen både tryggere og enklere å forstå.

1) Inputvalidering først

Den viktigste feilskjermen er validering i starten av hver handler: sjekk HTTP-metode, skjema, type og tomme felt før forretningslogikk.

funksjon safe_kontakt_handler(method: tekst, path: tekst, query: tekst, body: tekst) -> tekst {
    hvis method != "POST" da {
        returner web.http_typed_input_feil_respons("method", "POST", "kun POST", method)
    }

    la navn: tekst = web.http_body_json_felt_tekst(body, "navn")
    hvis navn == "" da {
        returner web.http_typed_input_feil_respons("body", "navn", "ikke tom", navn)
    }

    hvis lengde(navn) > 60 da {
        returner web.http_typed_input_feil_respons("body", "navn", "maks 60 tegn", navn)
    }

    returner web.http_json_respons("{\"ok\":true,\"status\":\"mottatt\"}")
}

Inputvalidering er viktig fordi det er her mange problemer kan stoppes før de blir systemtilstand, loggstøy eller sikkerhetsrisiko. Når ugyldige verdier først slipper inn, må resten av systemet tåle dem eller rydde dem opp senere. Det er både dyrere og mer sårbart.

Det holder heller ikke å sjekke om et felt finnes. Du vil ofte vite om det er tomt, for langt, har ugyldig format eller inneholder tegn som ødelegger downstream-behandling. Jo tydeligere reglene er ved inngangen, jo enklere blir resten av koden.

2) Autentisering og autorisasjon

Del ansvar i to lag: autentisering (hvem) og autorisering (hva de får lov til). Ikke la én sjekk dekke begge.

Autentisering

Bruk API-nøkler, sessions eller tokens. Sjekk token før du gjør noe annet.

Autorisering

Kontroller roller per endpoint. Minst-privilegium gjelder også i Norscode-prosjekter.

funksjon sjekk_token(token: tekst) -> bool {
    returner token == "norscode-premium-token"
}

funksjon admin_handler(method: tekst, path: tekst, query: tekst, body: tekst) -> tekst {
    la token: tekst = "norscode-premium-token"
    hvis ikke sjekk_token(token) da {
        returner web.http_unauthorized_respons("Manglende eller ugyldig token")
    }
    returner web.http_json_respons("{\"ok\":true,\"rolle\":\"admin\"}")
}

Dette skillet er viktig fordi mange sårbarheter oppstår når man tenker at “innlogget” automatisk betyr “har tilgang”. En bruker kan være ekte, men fortsatt mangle rettighet til en handling, en ressurs eller et admin-endepunkt. Når autentisering og autorisering blandes sammen, blir slike grenser uklare.

Minst-privilegium er et godt styringsprinsipp her. Gi bare den tilgangen som trengs for oppgaven, og bygg eksplisitte sjekker rundt sensitive operasjoner. Det gjør feil mindre farlige og revisjon enklere.

3) Nettverks- og trafikkvern

Skal du la andre integrasjoner treffe API-et ditt, beskytt med enkel rate limiting, CORS for riktig frontend, og whitelist på sensitive endepunkter.

Advarsel: åpne alle metoder i åpne GET-endepunkter gir mindre risiko enn åpne POST uten validering og rate-beskyttelse.

Nettverksvern handler om å redusere angrepsflaten før forespørsler i det hele tatt når forretningslogikken. Rate limiting, CORS, IP-begrensning og tydelige metodegrenser er en måte å si at ikke alt skal være mulig fra alle steder hele tiden.

Dette er spesielt viktig for endepunkter som skriver data, sender e-post, starter jobber eller snakker med eksterne systemer. Slike ruter bør behandles som dyrere og mer sensitive enn rene leseruter.

4) Robust feilhåndtering

Unngå rå feilmeldinger. Returner standardiserte, maskerte feil med tydelig status.

funksjon robust_handler(method: tekst, path: tekst, query: tekst, body: tekst) -> tekst {
    hvis method != "GET" da {
        returner web.http_respons_tekst(405, web.http_content_type_json(), "{\"error\":\"method_not_allowed\"}")
    }

    test {
        returner web.http_json_respons("{\"ok\":true}")
    } fang (err: tekst) {
        returner web.http_typed_internal_error_respons("server", err)
    }
}

Feilhåndtering er en sikkerhetsmekanisme fordi den styrer hvor mye systemet avslører når noe går galt. Hvis klienten får stacktraces, interne filstier eller rå detaljfeil, får også en angriper innsikt i hvordan løsningen er bygget og hvor den er svak.

Det beste mønsteret er ofte å ha tydelige, standardiserte klientfeil og mer detaljerte interne logger. Da kan drift og utvikling fortsatt forstå problemet uten at svarflaten blir unødvendig informativ for utenforstående.

5) Hemmeligheter og konfigurasjon

API-nøkler, admin-passord, tokens og andre hemmeligheter bør aldri hardkodes i vanlige filer. De bør hentes fra miljø eller en sikker konfigurasjonskilde, roteres ved behov og holdes utenfor logger, dumps og feilmeldinger.

En vanlig feil er at hemmeligheter dukker opp i støtteverktøy rundt koden: eksempeldata, lokale testfiler, shell-historikk eller verbose logger. Derfor bør sikker konfigurasjon sees som en del av hele arbeidsflyten, ikke bare som en egenskap ved produksjonsserveren.

6) Logging for sikker drift

Logg hendelser som hjelper drift, ikke detaljer som kan lekke sensitiv informasjon. Logg hendelses-id, request-id og årsak.

Inkluder alltid korrelasjons-ID på hele request-aksen.
funksjon logg_hendelse(kilde: tekst, melding: tekst) -> tekst {
    la ts: tekst = tid_nå()
    returner "[" + ts + "] " + kilde + ": " + melding
}

Logger er nyttige for å oppdage misbruk, feilsøke avvik og dokumentere hva som faktisk skjedde. Samtidig er de en potensiell lekkasjeflate. Derfor bør de være detaljerte nok til å hjelpe drift, men stramme nok til å ikke bli en kopi av sensitive request-data.

Et godt spørsmål er: hvis denne logglinjen dukker opp i feil dashboard eller sendes videre til et annet system, er den fortsatt trygg? Hvis svaret er nei, bør feltet maskeres, forkortes eller tas bort.

7) Sikkerhets-checkliste

  1. Validere input i hver handler.
  2. Bruke korrekt content-type på alle svar.
  3. Skille autentisering og autorisasjon.
  4. Rate-limit og CORS der det trengs.
  5. Standardisere feilmeldinger for klient, men ha detaljert intern logg.
  6. Kjøre test for ugyldig input og uvanlige kombinasjoner.

En sjekkliste gjør sikkerhet konkret. I stedet for å anta at løsningen “sannsynligvis er grei”, får teamet en fast måte å bekrefte at de viktigste kontrollene faktisk er på plass før release eller større endringer.

8) Anti-patterns

Disse mønstrene er farlige fordi de gjerne oppstår gradvis. Ett unntak blir til to, og etter hvert er sikkerhetsmodellen full av små hull som ingen lenger ser som spesielle. Derfor er det nyttig å navngi anti-patterns eksplisitt, så de blir lettere å kjenne igjen i kodegjennomgang og drift.

9) Hva som ofte går galt i praksis

De vanligste sikkerhetsproblemene i mindre webprosjekter er ofte ikke avanserte angrep, men en kombinasjon av slurv og uklarhet: for åpne endepunkter, for svak inputkontroll, for mye tillit til klienten, for brede tokens og for detaljerte logger. Når slike ting kombineres, blir det lett å misbruke systemet uten at det var noens opprinnelige hensikt.

Den gode nyheten er at disse problemene ofte kan reduseres mye med ganske enkle grep. Tydelige grenser, faste mønstre og en liten sikkerhetsgjennomgang før release gir stor effekt.

10) Når du er ferdig

Ta denne siden sammen med deploy-guiden, logging og