Emne

HMAC-validering

HMAC-validering er den måde, FastOG verificerer, at hver abonnementsbaseret OG-billedanmodning kommer fra din egen server – signerede URL'er beskytter dine credits. Opret en konto, vælg derefter en Dynamic API-plan, og opret din API-nøgle og HMAC-hemmelighed i dashboardet; betalte API-renderinger er rene. Denne side dækker server-side-reglerne bag dynamiske Open Graph-billeder, fra kanonisk forespørgselssignering til konstant-tids-sammenligning.

Oversigt

Der er tilføjet validering af HMAC-SHA256-signaturer til /api/v1/og-endepunktet for at forhindre uautoriseret brug af API-kvoten. Dette sikrer, at kun forespørgsler fra det legitime website kan generere OG-billeder.

Arkitektur

To-lags godkendelse:

  1. HMAC-signatur (først) – Validerer, at anmodningen stammer fra en betroet kilde (websitet)
  2. API-nøgle (derefter) – Identificerer brugerkontoen til afregning af render-kvote

Enkelt middleware (ApiKeyAuth): verificerer signaturen (query-parametre) og løser API-nøglen til afregning af render-kvote i ét gennemløb – fejl hurtigt ved ugyldige signaturer.

Query-parametre, ikke headere: Da OG-billeder hentes af sociale netværkscrawlere (LinkedIn, Twitter, Facebook), som ikke sender brugerdefinerede headere, sendes signaturen i URL-query-parametre:

GET /api/v1/og?title=Hello&key=sk_quick_123abc&s=<hmac>

Implementering

Oprettede/ændrede filer

  • app/Http/Middleware/HmacSignature.php - Ny middleware, der validerer HMAC-signaturer (query-parametre)
  • routes/api.php - Tilføjet HMAC-middleware til OG-ruten
  • bootstrap/app.php - Registreret hmac-middleware-alias
  • app/Models/ApiKey.php - Tilføjet hmac_secret-felt (hemmeligheder pr. bruger)
  • app/Http/Controllers/DashboardController.php - Genererer HMAC-hemmelighed ved oprettelse af API-nøgle
  • database/migrations/2026_08_03_214931_add_hmac_secret_to_api_keys_table.php - Migration til hmac_secret-kolonne
  • resources/js/Pages/Dashboard/ApiKeys.svelte - Viser HMAC-hemmelighed til brugeren (én gang)
  • docs/hmac-signature-guide.md - Implementeringsguide til klienter
  • tests/Feature/HmacSignatureTest.php - 8 bestående tests

Signaturalgoritme

method = HTTP method (e.g., "GET")
path  = request path (e.g., "/api/v1/og")
query = the request's DECODED query params

canonical = every param except `s`, keys sorted (array values sorted too),
            each `key=value` RFC-3986 encoded (unreserved-only), joined with "&"
message   = method + "/" + path + "\n" + canonical
signature = HMAC-SHA256(message, hmac_secret)

Query parameters:
  key=<apiKey>
  s=<signature>
  (no timestamp)

key er en del af den kanoniske query, så signaturen er bundet til API-nøglen. Ændring af en hvilken som helst parameter (titel, skabelon, billede, …) eller selve nøglen ændrer den kanoniske streng → signaturmismatch → 401 → ingen rendering, ingen kvotetælling. Identiske parametre → identisk signatur → identisk URL → kan cachelagres ved kanten for evigt, afspilles uden at tælle.

Sikkerhedsfunktioner

  • Indholdsadresseret signatur - Enhver parameterændring → 401 → ingen rendering, ingen kvotetælling (URL'en er i sig selv beviset)
  • Ingen tidsstempel - URL'er indlejres i offentlig HTML og cachelagres for evigt; de skal overleve 5 minutter
  • Konstant-tids-sammenligning (hash_equals()) - Forhindrer timing-angreb
  • API-nøgle i beskeden - Signaturen er bundet til nøglen; udskiftning af nøgler fejler
  • Stispecifik - Signatur er kun gyldig for den præcise sti
  • Metodespecifik - GET-signatur virker ikke til POST
  • Hemmeligheder pr. bruger - Hver API-nøgle har sin egen HMAC-hemmelighed, som kan tilbagekaldes uafhængigt (rotation = kill switch for lækkede URL'er)

Konfiguration

Generering af hemmelig nøgle (automatisk)

HMAC-hemmeligheden genereres automatisk, når du opretter en API-nøgle i dashboardet. Den vises én gang sammen med API-nøglen og vises derefter aldrig igen.

Manuel generering (hvis nødvendigt):

bash
openssl rand -hex 32

Databaseskema

sql
ALTER TABLE api_keys ADD COLUMN hmac_secret VARCHAR(64)
  COMMENT 'HMAC-SHA256 secret for signing OG image URLs (hex, 64 chars)';

Miljøvariabler

Der er ingen global miljøvariabel nødvendig – hemmeligheder gemmes pr. bruger i tabellen api_keys.

Brugseksempel (Website Backend)

javascript
// Node.js example - generate signed OG image URL
const crypto = require("crypto");

// RFC-3986 encode (encodeURIComponent leaves !'()* unencoded).
const enc = (s) =>
    encodeURIComponent(s).replace(
        /[!'()*]/g,
        (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase(),
    );

function generateOgImageUrl(baseUrl, params, apiKey, hmacSecret) {
    const all = { ...params, key: apiKey };

    // Canonical: every param (except s), sorted, RFC-3986 encoded, joined with "&".
    const pairs = [];
    for (const [k, v] of Object.entries(all)) {
        for (const vv of Array.isArray(v) ? [...v].sort() : [v])
            pairs.push(`${enc(k)}=${enc(vv)}`);
    }
    pairs.sort();
    const canonical = pairs.join("&");

    const message = `GET/api/v1/og\n${canonical}`;
    const signature = crypto
        .createHmac("sha256", hmacSecret)
        .update(message)
        .digest("hex");

    const url = new URL(baseUrl);
    for (const [k, v] of Object.entries(all)) {
        const isArray = Array.isArray(v);
        for (const vv of isArray ? v : [v])
            url.searchParams.append(isArray ? `${k}[]` : k, vv);
    }
    url.searchParams.set("s", signature);
    return url.toString();
}

// Usage in meta tag
const ogUrl = generateOgImageUrl(
    "https://fastog.com/api/v1/og",
    { title: "Como criar um SaaS", template: "blog" },
    "sk_quick_123abc",
    process.env.HMAC_SECRET,
);

// <meta property="og:image" content="{ogUrl}" />

Fejlresponser

Status Kode Beskrivelse
401 missing_signature Manglende key- eller s-forespørgselsparameter
401 invalid_signature Signatur matcher ikke den kanoniske forespørgsel (manipuleret eller forkert hemmelighed)

Testning

Kør testene:

bash
php artisan test --filter HmacSignatureTest

Alle 8 tests består:

  • ✅ Anmodning uden signatur afvises
  • ✅ Anmodning med manglende nøgleparameter afvises
  • ✅ Manipuleret indholdsparameter (titel ændret) afvises
  • ✅ Tilføjet parameter afvises
  • ✅ Ugyldig signatur afvises
  • ✅ Gyldig signatur består HMAC-kontrollen
  • ✅ Signatur er sti-specifik
  • ✅ Signatur er metode-specifik
  • ✅ Forskellige API-nøgler har forskellige hemmeligheder

Ydeevnepåvirkning

  • Ubetydelig – HMAC-SHA256-beregning tager ~0,1 ms pr. anmodning
  • Ingen ekstra netværkskald – Validering er lokal
  • Fejler hurtigt – Ugyldige signaturer afvises, før API-nøgleopslag finder sted

Sikkerhedsovervejelser

  1. Udsæt aldrig hemmeligheden i klientsidekode – signér kun på serveren
  2. Brug HTTPS – HMAC beskytter mod uautoriserede anmodninger, HTTPS beskytter mod MITM
  3. Roter hemmeligheder jævnligt – især hvis de er kompromitteret (kræver regenerering af API-nøgle)
  4. Overvåg fejlede signaturer – gentagne fejl kan indikere angreb
  5. Per-bruger-isolering – hver API-nøgle har sin egen HMAC-hemmelighed, så kompromittering af én påvirker ikke de andre

Referencer

Fuld API-referencen

Prøv det gratis – ingen tilmelding nødvendig

Forhåndsvis og test dynamiske OG-billeder på få sekunder.

Åbn den gratis OG-billedtester

A BeCaSimulations site