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:
- Tanda Tangan HMAC (pertama) - Memvalidasi bahwa permintaan berasal dari sumber tepercaya (situs web)
- 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 OGbootstrap/app.php- Mendaftarkan alias middlewarehmacapp/Models/ApiKey.php- Menambahkan kolomhmac_secret(rahasia per pengguna)app/Http/Controllers/DashboardController.php- Menghasilkan rahasia HMAC saat pembuatan kunci APIdatabase/migrations/2026_08_03_214931_add_hmac_secret_to_api_keys_table.php- Migrasi untuk kolom hmac_secretresources/js/Pages/Dashboard/ApiKeys.svelte- Menampilkan rahasia HMAC kepada pengguna (sekali saja)docs/hmac-signature-guide.md- Panduan implementasi klientests/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):
openssl rand -hex 32
Skema Basis Data
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)
// 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:
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
- Jangan pernah mengekspos secret di kode sisi klien - Tandatangani hanya di server
- Gunakan HTTPS - HMAC melindungi dari permintaan tidak sah, HTTPS melindungi dari MITM
- Rotasi secret secara berkala - Terutama jika telah disusupi (memerlukan regenerasi kunci API)
- Pantau tanda tangan yang gagal - Kegagalan berulang dapat mengindikasikan serangan
- Isolasi per pengguna - Setiap kunci API memiliki secret HMAC sendiri, kompromi pada satu tidak memengaruhi yang lain
Referensi
- Panduan Tanda Tangan HMAC untuk Klien
- Panduan Memulai Cepat
- OWASP: Lembar Curang Penyimpanan Kriptografi
- PHP: hash_hmac()