Sikkerhed

Sikkerhedsoverblik for Ressourcify — fra organisationens beslutningstager til kundens sikkerhedsteam.

Denne side har to lag: et overblik for ledere og indkøbere øverst, og en teknisk dybde længere nede for sikkerhedsteams og auditorer.


Overblik

Ressourcify er bygget med fire principper:

PrincipHvad det betyder
SSO som standardLogin går altid via din egen Microsoft Entra ID. Vi gemmer aldrig adgangskoder.
Defense in depthAdgang er låst på applikations-, database- og infrastruktur-niveau — ikke kun ét sted.
Tenant-isolationHver organisations data er isoleret. En medarbejder kan aldrig se en anden organisations indhold.
SporbarhedHver kritisk handling logges. Vi kan altid svare på "hvem ændrede hvad hvornår?"

Hvad du som beslutningstager skal vide

  • Identitet: Vi har ingen egen brugerdatabase med adgangskoder. Brugere oprettes ved første login via Microsoft Entra. Hvis du fjerner en bruger fra Entra, mister vedkommende straks adgang ved næste session-fornyelse (max 12 timer).
  • Adgangskontrol: Fem roller (ORG_ADMIN, DEPT_ADMIN, COORDINATOR, RESOURCE, VIEWER) styret centralt via Entra-sikkerhedsgrupper. Du behøver ikke vedligeholde adgang to steder.
  • Data: Hostet hos Supabase i EU (Frankfurt). Krypteret in transit (TLS 1.3) og at rest (AES-256).
  • Audit: Hver mutation logges med før/efter-tilstand. Default retention 365 dage, konfigurerbar op til 5 år.
  • GDPR: Databehandler-aftale er tilgængelig på anmodning. Data slettes ved opsigelse efter aftalt udfasningsperiode.

Hvad du som bruger ser

  • Du kan ikke se data fra andre organisationer.
  • Du kan kun ændre data du har eksplicit ret til (din egen — eller dem du administrerer som koordinator/admin).
  • Audit-loggen ser kun ORG_ADMIN.

Teknisk dybde

For kundens sikkerhedsteam og auditorer. Forudsætter generel kendskab til web-sikkerhed.

Identitets-arkitektur

Browser → Next.js → Microsoft Entra ID (OIDC)

         Postgres (brugere + roller)
  • Provider: Microsoft Entra ID (Azure AD) via OIDC, scope openid profile email
  • NextAuth v5 håndterer OIDC-flow, nonce-validering, state, PKCE
  • Sessioner: JWT i HttpOnly; Secure; SameSite=Lax cookie, signeret med HS256 + AUTH_SECRET
  • Session-levetid: 12 timer. Re-auth efter 12t går silent via Entra hvis brugeren stadig er logget ind på Microsoft
  • Ingen lokale credentials: passwordHash-kolonnen findes på User-modellen men benyttes ikke i produktion

Se Auth-flow for komplet sekvensdiagram.

Adgangskontrol (RBAC)

Tre lag — alle skal være tilfredse før en handling tillades:

  1. Session-tjek: auth() validerer JWT-signaturen og henter brugerens roller fra DB
  2. can()-tjek: lib/authz.ts evaluerer rolle × ressource × handling × scope
  3. Postgres Row-Level Security: Forsvarslag #3 hvis app-koden skulle have en bug

Roller, scopes og handlinger: RBAC-matrix.

Tenant-isolation

Alle queries filtrerer på organizationId fra sessionen. Modeller uden direkte organizationId (fx Assignment) arver isolation fra parent.

Row-Level Security: Alle 34 public-tabeller har RLS-policies som afviser læsning hvis current_setting('app.organization_id') ikke matcher række-organisationen. Prisma's tjenestekonto ejer tabellerne og bypasser RLS — så app-koden virker, men anden adgangsvej blokeres:

  • Direkte JDBC/psql-forespørgsler fra ikke-tjenestekonto: blokeret
  • Supabase PostgREST med anon-rolle: blokeret
  • En lækket bruger-JWT brugt mod databasen: blokeret

Hemmeligheder

HemmelighedHvor
AUTH_SECRET (JWT-signering)Vercel env, krypteret at rest
AUTH_MICROSOFT_ENTRA_ID_SECRET (Entra client secret)Krypteret med ENCRYPTION_KEY i EntraConfig-tabel — alternativt env-fallback
DATABASE_URL, DIRECT_URLVercel env, kun læselige af Vercel-runtime
ENCRYPTION_KEY (AES-256-GCM til client secret)Vercel env, separat fra database

Krypteringen er AES-256-GCM med 96-bit nonce per ciphertext. Klartekst ses aldrig i logs.

Audit-log

Hver CREATE/UPDATE/DELETE på kritiske entiteter giver en AuditLog-række med før- og efter-snapshot. Følsomme felter (passwordHash, krypterede secrets) redactes til "<redacted>".

  • Tabel: AuditLog i samme database som operationelle data
  • Retention: Konfigurabel per organisation (90/180/365/730/1825 dage). Default 365.
  • Autoprune: Daglig cron-lignende job sletter rækker ældre end retention. Idempotent.
  • Eksport: ORG_ADMIN kan eksportere som CSV. Eksport-handlingen logger selv et EXPORT-event.
  • Tilgang: Kun ORG_ADMIN. Ingen anden rolle har adgang.

Se Audit-log for fuld dækningsliste og felt-skema.

Input-validering

Hvert API-endpoint har fire valideringslag:

LagVærktøjEffekt
Sessionauth()401 hvis ikke logget ind
Authzcan()403 hvis utilstrækkelig rolle
BodyZod safeParse422 ved skema-fejl
QueryZod safeParse422 ved skema-fejl

UUID-validering er separat (samme uuidSchema.safeParse). Vi bruger aldrig Zod's parse — kun safeParse, så uventede inputs ikke kaster uncaught exceptions.

Fejl-håndtering

API'et returnerer RFC 7807 Problem Details. Fejl-svar indeholder aldrig:

  • Stack traces
  • Database-query'er
  • Andre brugeres data
  • Filsystem-stier

Cross-organisation requests svarer med 404 (ikke 403) for ikke at lække ressource-eksistens.

Hosting og netværk

  • Application: Vercel (EU-region)
  • Database: Supabase (Frankfurt, EU)
  • Transport: TLS 1.3, HSTS, sikre cookies, Content-Security-Policy
  • Web Application Firewall: Vercel's indbyggede WAF

Threat model — kort

TrusselModforanstaltning
Stjålet bruger-JWT12t-levetid + HttpOnly cookie + signatur-validering
Privilege escalation via gruppe-manipulationKun Entra-administratorer kan ændre grupper; ændringer kræver re-login
Cross-tenant data-lækageApp-filter + RLS som dobbelt-sikring
SQL injectionPrisma med parameteriserede queries
XSSReact's default-escaping + CSP-headers
CSRFSameSite=Lax cookie + NextAuth's indbyggede CSRF-token
Supply chainLock-file committed; pnpm verify-store-integrity; dependabot
Insider threatAudit-log, separation of duties (kun ORG_ADMIN kan ændre roller eller retention)

Compliance

  • GDPR: Databehandler-aftale på anmodning. Soft-delete på User bevarer audit-trail uden persondata.
  • Datafortrolighed: TLS 1.3 i transit, AES-256 at rest (Supabase + krypteret client secret)
  • Subprocessorer: Microsoft (Entra), Supabase, Vercel. Liste opdateres ved ændringer.

Ansvarlig fremgangsmåde ved fund

Skriv til security@ressourcify.dk (eller den kontakt der er angivet i din kontrakt). Vi svarer inden 48 timer og koordinerer offentliggørelse i samarbejde med dig.

Vi har ikke et formelt bug bounty endnu — men anerkender alle indrapporter offentligt med samtykke.

On this page