التحقق من HMAC
التحقق من HMAC هو الطريقة التي يتحقق بها FastOG من أن كل طلب صورة OG قائم على الاشتراك جاء من خادمك الخاص — فالعناوين الموقّعة تحافظ على أمان رصيدك. سجّل للحصول على حساب، ثم اختر خطة API الديناميكية وأنشئ مفتاح API وسر HMAC في لوحة التحكم؛ عمليات عرض API المدفوعة تكون نظيفة. تغطي هذه الصفحة القواعد من جانب الخادم وراء الصور الديناميكية لـ Open Graph، بدءًا من توقيع الاستعلام الأساسي وصولًا إلى المقارنة في وقت ثابت.
نظرة عامة
تمت إضافة التحقق من التوقيع باستخدام HMAC-SHA256 إلى نقطة النهاية /api/v1/og لمنع الاستخدام غير المصرح به لحصة واجهة برمجة التطبيقات (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 إلى مسار OGbootstrap/app.php- تسجيل اسم مستعارhmacللوسيطapp/Models/ApiKey.php- إضافة حقلhmac_secret(أسرار لكل مستخدم)app/Http/Controllers/DashboardController.php- توليد سر HMAC عند إنشاء مفتاح APIdatabase/migrations/2026_08_03_214931_add_hmac_secret_to_api_keys_table.php- ترحيل (migration) لعمود 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 جزء من الاستعلام الأساسي (canonical query)، لذا فإن التوقيع مرتبط بمفتاح API. تغيير أي معامل (العنوان، القالب، الصورة، …) أو المفتاح نفسه يغيّر الاستعلام الأساسي ← عدم تطابق التوقيع ← 401 ← لا يتم العرض، ولا يُحتسب من الحصة. معاملات متطابقة ← توقيع متطابق ← URL متطابق ← قابل للتخزين المؤقت (cache) عند الحافة إلى الأبد، ويُعاد استخدامه دون احتساب.
ميزات الأمان
- توقيع مرتبط بالمحتوى - أي تغيير في المعاملات ← 401 ← لا يتم العرض، ولا يُحتسب من الحصة (الـ URL نفسه هو الإثبات)
- بدون طابع زمني - تُضمَّن الـ URLs في HTML عام وتُخزَّن مؤقتًا إلى الأبد؛ يجب أن تتجاوز صلاحيتها 5 دقائق
- مقارنة بزمن ثابت (
hash_equals()) - تمنع هجمات التوقيت (timing attacks) - مفتاح API ضمن الرسالة - التوقيع مرتبط بالمفتاح؛ تبديل المفاتيح يفشل
- خاص بالمسار - التوقيع صالح فقط للمسار المحدد
- خاص بالطريقة - توقيع GET لن يصلح لـ POST
- أسرار لكل مستخدم - لكل مفتاح API سر HMAC خاص به، ويمكن إبطاله بشكل مستقل (التدوير = مفتاح إيقاف للـ URLs المسرّبة)
الإعداد
توليد السر (تلقائيًا)
يتم توليد سر 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
جميع الاختبارات الثمانية تنجح:
- ✅ يتم رفض الطلب بدون توقيع
- ✅ يتم رفض الطلب الذي يحتوي على معامل مفتاح مفقود
- ✅ يتم رفض معامل المحتوى المعدّل (تم تغيير العنوان)
- ✅ يتم رفض المعامل المضاف
- ✅ يتم رفض التوقيع غير الصالح
- ✅ التوقيع الصالح يجتاز فحص HMAC
- ✅ التوقيع خاص بالمسار
- ✅ التوقيع خاص بالطريقة
- ✅ مفاتيح API المختلفة لها أسرار مختلفة
تأثير الأداء
- ضئيل - حساب HMAC-SHA256 يستغرق حوالي 0.1 مللي ثانية لكل طلب
- لا مكالمات شبكة إضافية - التحقق يتم محليًا
- فشل سريع - يتم رفض التوقيعات غير الصالحة قبل البحث عن مفتاح API
اعتبارات الأمان
- لا تكشف السر أبدًا في كود جانب العميل - وقّع على الخادم فقط
- استخدم HTTPS - يحمي HMAC من الطلبات غير المصرح بها، ويحمي HTTPS من هجمات الوسيط (MITM)
- قم بتدوير الأسرار بشكل دوري - خاصة إذا تم اختراقها (يتطلب إعادة توليد مفتاح API)
- راقب التوقيعات الفاشلة - قد تشير حالات الفشل المتكررة إلى هجمات
- عزل لكل مستخدم - لكل مفتاح API سر HMAC خاص به، واختراق أحدها لا يؤثر على الآخرين