Перевірка HMAC
Перевірка HMAC — це спосіб, за допомогою якого FastOG підтверджує, що кожен запит на OG-зображення на основі підписки надійшов із вашого власного сервера — підписані URL-адреси захищають ваші кредити. Зареєструйтеся, оберіть тариф Dynamic API та створіть свій API-ключ і HMAC-секрет у панелі керування (dashboard); платні API-рендери є чистими. Ця сторінка охоплює серверні правила, що стоять за динамічними зображеннями Open Graph, від канонічного підписування запиту до порівняння за константний час.
Огляд
До кінцевої точки /api/v1/og додано перевірку підпису HMAC-SHA256, щоб запобігти несанкціонованому використанню квоти API. Це гарантує, що лише запити з легітимного вебсайту можуть генерувати OG-зображення.
Архітектура
Двошарова автентифікація:
- HMAC-підпис (перший) — підтверджує, що запит надійшов із довіреного джерела (вебсайту)
- 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— зареєстровано псевдонім проміжного ПЗhmacapp/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_secretresources/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-ключем, після чого більше не показується.
Ручна генерація (за потреби):
openssl rand -hex 32
Схема бази даних
ALTER TABLE api_keys ADD COLUMN hmac_secret VARCHAR(64)
COMMENT 'HMAC-SHA256 secret for signing OG image URLs (hex, 64 chars)';
Змінні середовища
Глобальна змінна середовища не потрібна — секрети зберігаються для кожного користувача в таблиці api_keys.
Приклад використання (бекенд вебсайту)
// 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 |
Підпис не збігається з канонічним запитом (змінено або неправильний секрет) |
Тестування
Запуск тестів:
php artisan test --filter HmacSignatureTest
Усі 8 тестів проходять успішно:
- ✅ Запит без підпису відхиляється
- ✅ Запит із відсутнім параметром ключа відхиляється
- ✅ Змінений параметр вмісту (змінено заголовок) відхиляється
- ✅ Доданий параметр відхиляється
- ✅ Недійсний підпис відхиляється
- ✅ Дійсний підпис проходить перевірку HMAC
- ✅ Підпис залежить від шляху
- ✅ Підпис залежить від методу
- ✅ Різні ключі API мають різні секрети
Вплив на продуктивність
- Незначний — обчислення HMAC-SHA256 займає ~0,1 мс на запит
- Без додаткових мережевих викликів — перевірка виконується локально
- Швидке відхилення — недійсні підписи відхиляються до пошуку API-ключа
Міркування щодо безпеки
- Ніколи не розкривайте секрет у клієнтському коді — підписуйте лише на сервері
- Використовуйте HTTPS — HMAC захищає від несанкціонованих запитів, HTTPS захищає від MITM
- Періодично змінюйте секрети — особливо у разі компрометації (потребує повторної генерації API-ключа)
- Відстежуйте невдалі підписи — повторні збої можуть свідчити про атаки
- Ізоляція за користувачем — кожен API-ключ має власний HMAC-секрет, компрометація одного не впливає на інші
Посилання
- Посібник із HMAC-підписів для клієнтів
- Посібник із швидкого старту
- OWASP: Шпаргалка з криптографічного зберігання
- PHP: hash_hmac()