Sujet

Validation HMAC

La validation HMAC est la méthode utilisée par FastOG pour vérifier que chaque requête d'image OG basée sur un abonnement provient bien de votre propre serveur — les URL signées protègent vos crédits. Inscrivez-vous, puis choisissez un plan Dynamic API et créez votre clé API et votre secret HMAC dans le tableau de bord ; les rendus API payants sont propres. Cette page couvre les règles côté serveur derrière les images Open Graph dynamiques, de la signature canonique des requêtes à la comparaison en temps constant.

Aperçu

La validation de signature HMAC-SHA256 a été ajoutée au point de terminaison /api/v1/og afin d’empêcher toute utilisation non autorisée du quota API. Cela garantit que seules les requêtes provenant du site web légitime peuvent générer des images OG.

Architecture

Authentification à deux niveaux :

  1. Signature HMAC (premier niveau) — Vérifie que la requête provient d'une source de confiance (le site web)
  2. Clé API (second niveau) — Identifie le compte utilisateur pour la comptabilisation du quota de rendu

Middleware unique (ApiKeyAuth) : vérifie la signature (paramètres de requête) et résout la clé API pour la comptabilisation du quota de rendu en une seule passe — échec rapide en cas de signature invalide.

Paramètres de requête, pas d'en-têtes : étant donné que les images OG sont récupérées par les robots des réseaux sociaux (LinkedIn, Twitter, Facebook) qui n'envoient pas d'en-têtes personnalisés, la signature est transmise dans les paramètres de requête de l'URL :

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

Implémentation

Fichiers créés/modifiés

  • app/Http/Middleware/HmacSignature.php - Nouveau middleware validant les signatures HMAC (paramètres de requête)
  • routes/api.php - Ajout du middleware HMAC à la route OG
  • bootstrap/app.php - Enregistrement de l'alias du middleware hmac
  • app/Models/ApiKey.php - Ajout du champ hmac_secret (secrets par utilisateur)
  • app/Http/Controllers/DashboardController.php - Génère le secret HMAC lors de la création de la clé API
  • database/migrations/2026_08_03_214931_add_hmac_secret_to_api_keys_table.php - Migration pour la colonne hmac_secret
  • resources/js/Pages/Dashboard/ApiKeys.svelte - Affiche le secret HMAC à l'utilisateur (une seule fois)
  • docs/hmac-signature-guide.md - Guide d'implémentation côté client
  • tests/Feature/HmacSignatureTest.php - 8 tests réussis

Algorithme de signature

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 fait partie de la requête canonique, la signature est donc liée à la clé API. Toute modification d'un paramètre (titre, template, image, …) ou de la clé elle-même modifie la requête canonique → non-concordance de signature → 401 → aucun rendu, aucun quota consommé. Des paramètres identiques → une signature identique → une URL identique → mise en cache en périphérie pour toujours, rejouée sans comptage.

Fonctionnalités de sécurité

  • Signature adressée par contenu - Toute modification d'un paramètre → 401 → aucun rendu, aucun quota consommé (l'URL elle-même est la preuve)
  • Pas d'horodatage - Les URL sont intégrées dans le HTML public et mises en cache pour toujours ; elles doivent survivre au-delà de 5 minutes
  • Comparaison en temps constant (hash_equals()) - Prévient les attaques temporelles
  • Clé API dans le message - La signature est liée à la clé ; changer de clé échoue
  • Spécifique au chemin - La signature n'est valide que pour le chemin exact
  • Spécifique à la méthode - Une signature GET ne fonctionne pas pour POST
  • Secrets par utilisateur - Chaque clé API possède son propre secret HMAC, révocable indépendamment (rotation = interrupteur d'arrêt pour les URL divulguées)

Configuration

Générer un secret (automatique)

Le secret HMAC est généré automatiquement lors de la création d’une clé API dans le tableau de bord. Il est affiché une seule fois avec la clé API, puis n’est plus jamais montré.

Génération manuelle (si nécessaire) :

bash
openssl rand -hex 32

Schéma de base de données

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

Variables d’environnement

Aucune variable d’environnement globale n’est requise — les secrets sont stockés par utilisateur dans la table api_keys.

Exemple d’utilisation (backend du site web)

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}" />

Réponses d’erreur

Statut Code Description
401 missing_signature Paramètre de requête key ou s manquant
401 invalid_signature La signature ne correspond pas à la requête canonique (altérée ou secret incorrect)

Tests

Exécutez les tests :

bash
php artisan test --filter HmacSignatureTest

Les 8 tests passent tous :

  • ✅ Une requête sans signature est rejetée
  • ✅ Une requête avec un paramètre de clé manquant est rejetée
  • ✅ Un paramètre de contenu modifié (titre changé) est rejeté
  • ✅ Un paramètre ajouté est rejeté
  • ✅ Une signature invalide est rejetée
  • ✅ Une signature valide passe le contrôle HMAC
  • ✅ La signature est spécifique au chemin
  • ✅ La signature est spécifique à la méthode
  • ✅ Des clés API différentes ont des secrets différents

Impact sur les performances

  • Négligeable - Le calcul HMAC-SHA256 prend environ 0,1 ms par requête
  • Aucun appel réseau supplémentaire - La validation est locale
  • Échec rapide - Les signatures invalides sont rejetées avant la recherche de la clé API

Considérations de sécurité

  1. Ne jamais exposer le secret dans le code côté client — Signez uniquement côté serveur
  2. Utilisez HTTPS — HMAC protège contre les requêtes non autorisées, HTTPS protège contre les attaques de l’homme du milieu (MITM)
  3. Faites pivoter les secrets périodiquement — Surtout en cas de compromission (nécessite la régénération de la clé API)
  4. Surveillez les signatures échouées — Des échecs répétés peuvent indiquer des attaques
  5. Isolation par utilisateur — Chaque clé API possède son propre secret HMAC ; la compromission de l’une n’affecte pas les autres

Références

Référence complète de l’API

Essayez gratuitement — aucune inscription requise

Prévisualisez et testez des images OG dynamiques en quelques secondes.

Ouvrir le testeur d'images OG gratuit

A BeCaSimulations site