Тема

Перевірка HMAC

Перевірка HMAC — це спосіб, за допомогою якого FastOG підтверджує, що кожен запит на OG-зображення на основі підписки надійшов із вашого власного сервера — підписані URL-адреси захищають ваші кредити. Зареєструйтеся, оберіть тариф Dynamic API та створіть свій API-ключ і HMAC-секрет у панелі керування (dashboard); платні API-рендери є чистими. Ця сторінка охоплює серверні правила, що стоять за динамічними зображеннями Open Graph, від канонічного підписування запиту до порівняння за константний час.

Огляд

До кінцевої точки /api/v1/og додано перевірку підпису HMAC-SHA256, щоб запобігти несанкціонованому використанню квоти API. Це гарантує, що лише запити з легітимного вебсайту можуть генерувати OG-зображення.

Архітектура

Двошарова автентифікація:

  1. HMAC-підпис (перший) — підтверджує, що запит надійшов із довіреного джерела (вебсайту)
  2. API-ключ (другий) — ідентифікує обліковий запис користувача для обліку квоти на рендеринг

Єдине проміжне програмне забезпечення (ApiKeyAuth): перевіряє підпис (параметри запиту) та визначає API-ключ для обліку квоти на рендеринг за один прохід — швидке відхилення запитів із некоректним підписом.

Параметри запиту, а не заголовки: оскільки OG-зображення отримуються краулерами соціальних мереж (LinkedIn, Twitter, Facebook), які не надсилають власні заголовки, підпис передається в параметрах URL-запиту:

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

Реалізація

Створені/змінені файли

  • app/Http/Middleware/HmacSignature.php — нове проміжне ПЗ (middleware) для перевірки HMAC-підписів (параметри запиту)
  • routes/api.php — додано HMAC-проміжне ПЗ до OG-маршруту
  • bootstrap/app.php — зареєстровано псевдонім проміжного ПЗ hmac
  • app/Models/ApiKey.php — додано поле hmac_secret (секрети для кожного користувача)
  • app/Http/Controllers/DashboardController.php — генерує HMAC-секрет під час створення API-ключа
  • database/migrations/2026_08_03_214931_add_hmac_secret_to_api_keys_table.php — міграція для колонки hmac_secret
  • resources/js/Pages/Dashboard/ApiKeys.svelte — показує HMAC-секрет користувачу (один раз)
  • docs/hmac-signature-guide.md — посібник із реалізації для клієнта
  • tests/Feature/HmacSignatureTest.php — 8 тестів, що проходять

Алгоритм підпису

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 є частиною канонічного запиту, тому підпис прив’язаний до API-ключа. Зміна будь-якого параметра (title, template, image, …) або самого ключа змінює канонічний запит → невідповідність підпису → 401 → без рендерингу, без обліку квоти. Ідентичні параметри → ідентичний підпис → ідентичний URL → кешується на межі мережі назавжди, відтворюється без обліку.

Функції безпеки

  • Підпис на основі вмісту — будь-яка зміна параметра → 401 → без рендерингу, без обліку квоти (сам URL є доказом)
  • Без часової мітки — URL вбудовуються в публічний HTML і кешуються назавжди; вони мають переживати 5 хвилин
  • Порівняння за сталий час (hash_equals()) — запобігає атакам за часом
  • API-ключ у повідомленні — підпис прив’язаний до ключа; заміна ключів призводить до помилки
  • Прив’язка до шляху — підпис дійсний лише для точного шляху
  • Прив’язка до методу — підпис для GET не спрацює для POST
  • Секрети для кожного користувача — кожен API-ключ має власний HMAC-секрет, який можна відкликати незалежно (ротація = аварійний вимикач для витоку URL)

Конфігурація

Генерація секрету (автоматично)

HMAC-секрет генерується автоматично під час створення API-ключа в панелі керування (dashboard). Він відображається один раз разом з API-ключем, після чого більше не показується.

Ручна генерація (за потреби):

bash
openssl rand -hex 32

Схема бази даних

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

Змінні середовища

Глобальна змінна середовища не потрібна — секрети зберігаються для кожного користувача в таблиці api_keys.

Приклад використання (бекенд вебсайту)

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

Відповіді про помилки

Статус Код Опис
401 missing_signature Відсутній параметр запиту key або s
401 invalid_signature Підпис не збігається з канонічним запитом (змінено або неправильний секрет)

Тестування

Запуск тестів:

bash
php artisan test --filter HmacSignatureTest

Усі 8 тестів проходять успішно:

  • ✅ Запит без підпису відхиляється
  • ✅ Запит із відсутнім параметром ключа відхиляється
  • ✅ Змінений параметр вмісту (змінено заголовок) відхиляється
  • ✅ Доданий параметр відхиляється
  • ✅ Недійсний підпис відхиляється
  • ✅ Дійсний підпис проходить перевірку HMAC
  • ✅ Підпис залежить від шляху
  • ✅ Підпис залежить від методу
  • ✅ Різні ключі API мають різні секрети

Вплив на продуктивність

  • Незначний — обчислення HMAC-SHA256 займає ~0,1 мс на запит
  • Без додаткових мережевих викликів — перевірка виконується локально
  • Швидке відхилення — недійсні підписи відхиляються до пошуку API-ключа

Міркування щодо безпеки

  1. Ніколи не розкривайте секрет у клієнтському коді — підписуйте лише на сервері
  2. Використовуйте HTTPS — HMAC захищає від несанкціонованих запитів, HTTPS захищає від MITM
  3. Періодично змінюйте секрети — особливо у разі компрометації (потребує повторної генерації API-ключа)
  4. Відстежуйте невдалі підписи — повторні збої можуть свідчити про атаки
  5. Ізоляція за користувачем — кожен API-ключ має власний HMAC-секрет, компрометація одного не впливає на інші

Посилання

Повна довідка API

Спробуйте безкоштовно — реєстрація не потрібна

Переглядайте та тестуйте динамічні OG-зображення за лічені секунди.

Відкрити безкоштовний тестер OG-зображень

A BeCaSimulations site