FastOG
Topik

Validasi HMAC

Validasi HMAC adalah cara FastOG memverifikasi bahwa setiap permintaan gambar OG berbasis langganan berasal dari server Anda sendiri — URL yang ditandatangani menjaga kredit Anda tetap aman. Daftar akun, lalu pilih paket Dynamic API dan buat kunci API serta rahasia HMAC Anda di dasbor; render API berbayar bersih. Halaman ini mencakup aturan sisi server di balik gambar Open Graph dinamis, mulai dari penandatanganan kueri kanonis hingga perbandingan waktu konstan.

Ringkasan

Validasi tanda tangan HMAC-SHA256 telah ditambahkan ke endpoint /api/v1/og untuk mencegah penggunaan kuota API secara tidak sah. Hal ini memastikan hanya permintaan dari situs web yang sah yang dapat menghasilkan gambar OG.

Arsitektur

Autentikasi dua lapis:

  1. Tanda Tangan HMAC (pertama) - Memvalidasi bahwa permintaan berasal dari sumber tepercaya (situs web)
  2. Kunci API (kedua) - Mengidentifikasi akun pengguna untuk pencatatan kuota render

Middleware tunggal (ApiKeyAuth): memverifikasi tanda tangan (parameter kueri) dan menyelesaikan kunci API untuk pencatatan kuota render dalam satu proses — gagal cepat pada tanda tangan yang tidak valid.

Parameter kueri, bukan header: Karena gambar OG diambil oleh perayap jaringan sosial (LinkedIn, Twitter, Facebook) yang tidak mengirimkan header kustom, tanda tangan diteruskan melalui parameter kueri URL:

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

Implementasi

Berkas yang Dibuat/Diubah

  • app/Http/Middleware/HmacSignature.php - Middleware baru untuk memvalidasi tanda tangan HMAC (parameter kueri)
  • routes/api.php - Menambahkan middleware HMAC ke rute OG
  • bootstrap/app.php - Mendaftarkan alias middleware hmac
  • app/Models/ApiKey.php - Menambahkan kolom hmac_secret (rahasia per pengguna)
  • app/Http/Controllers/DashboardController.php - Menghasilkan rahasia HMAC saat pembuatan kunci API
  • database/migrations/2026_08_03_214931_add_hmac_secret_to_api_keys_table.php - Migrasi untuk kolom hmac_secret
  • resources/js/Pages/Dashboard/ApiKeys.svelte - Menampilkan rahasia HMAC kepada pengguna (sekali saja)
  • docs/hmac-signature-guide.md - Panduan implementasi klien
  • tests/Feature/HmacSignatureTest.php - 8 pengujian yang lulus

Algoritma Tanda Tangan

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 merupakan bagian dari kueri kanonik, sehingga tanda tangan terikat pada kunci API. Mengubah parameter apa pun (judul, templat, gambar, …) atau kunci itu sendiri akan mengubah kanonik → ketidakcocokan tanda tangan → 401 → tidak ada render, tidak ada hitungan kuota. Parameter yang identik → tanda tangan yang identik → URL yang identik → dapat di-cache di edge selamanya, diputar ulang tanpa dihitung.

Fitur Keamanan

  • Tanda tangan dengan alamat konten - Perubahan parameter apa pun → 401 → tidak ada render, tidak ada hitungan kuota (URL itu sendiri adalah buktinya)
  • Tanpa stempel waktu - URL disematkan dalam HTML publik + di-cache selamanya; URL harus bertahan lebih dari 5 menit
  • Perbandingan waktu konstan (hash_equals()) - Mencegah serangan timing
  • Kunci API dalam pesan - Tanda tangan terikat pada kunci; mengganti kunci akan gagal
  • Khusus jalur - Tanda tangan hanya valid untuk jalur yang tepat
  • Khusus metode - Tanda tangan GET tidak akan berfungsi untuk POST
  • Rahasia per pengguna - Setiap kunci API memiliki rahasia HMAC sendiri, dapat dicabut secara independen (rotasi = saklar pemutus untuk URL yang bocor)

Konfigurasi

Membuat Secret (Otomatis)

Secret HMAC dibuat secara otomatis saat membuat kunci API di dasbor. Secret ini ditampilkan satu kali bersama dengan kunci API, lalu tidak akan pernah ditampilkan lagi.

Pembuatan manual (jika diperlukan):

bash
openssl rand -hex 32

Skema Basis Data

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

Variabel Lingkungan

Tidak diperlukan variabel lingkungan global - secret disimpan per pengguna di tabel api_keys.

Contoh Penggunaan (Backend Situs 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}" />

Respons Kesalahan

Status Kode Deskripsi
401 missing_signature Parameter kueri key atau s tidak ada
401 invalid_signature Tanda tangan tidak cocok dengan kueri kanonik (diubah atau kunci rahasia salah)

Pengujian

Jalankan pengujian:

bash
php artisan test --filter HmacSignatureTest

Semua 8 pengujian berhasil:

  • ✅ Permintaan tanpa tanda tangan ditolak
  • ✅ Permintaan dengan parameter kunci yang hilang ditolak
  • ✅ Parameter konten yang diubah (judul diubah) ditolak
  • ✅ Parameter tambahan ditolak
  • ✅ Tanda tangan tidak valid ditolak
  • ✅ Tanda tangan valid lolos pemeriksaan HMAC
  • ✅ Tanda tangan spesifik terhadap jalur
  • ✅ Tanda tangan spesifik terhadap metode
  • ✅ Kunci API yang berbeda memiliki rahasia yang berbeda

Dampak Kinerja

  • Dapat Diabaikan - Perhitungan HMAC-SHA256 sekitar 0,1ms per permintaan
  • Tidak ada panggilan jaringan tambahan - Validasi dilakukan secara lokal
  • Gagal dengan cepat - Tanda tangan yang tidak valid ditolak sebelum pencarian kunci API

Pertimbangan Keamanan

  1. Jangan pernah mengekspos secret di kode sisi klien - Tandatangani hanya di server
  2. Gunakan HTTPS - HMAC melindungi dari permintaan tidak sah, HTTPS melindungi dari MITM
  3. Rotasi secret secara berkala - Terutama jika telah disusupi (memerlukan regenerasi kunci API)
  4. Pantau tanda tangan yang gagal - Kegagalan berulang dapat mengindikasikan serangan
  5. Isolasi per pengguna - Setiap kunci API memiliki secret HMAC sendiri, kompromi pada satu tidak memengaruhi yang lain

Referensi

Referensi API Lengkap

Coba gratis — tanpa perlu mendaftar

Pratinjau dan uji gambar OG dinamis dalam hitungan detik.

Buka Penguji Gambar OG Gratis

A BeCaSimulations site