DAT (Distributed Access Token)
1. نظرة عامة
مع تزايد عدد المستخدمين المتصلين في وقت واحد، يزداد عدد الجلسات (Sessions) بالتوازي، مما يُسبّب ضغطاً زائداً على خادم الجلسات.
DAT هو مواصفة رمز (Token Spec) صُمِّمت لحل مشكلة الضغط على خادم الجلسات، ولتحقيق مصادقة فعّالة لا تتطلب مشاركة الحالة بين الخوادم (Stateless).
يتكوّن DAT من سلسلة نصية مؤلفة من خمسة حقول ثابتة مفصولة بنقاط (.). يمكن اقتطاع كل حقل بالاعتماد على موضع الفاصل وحده دون أي تحليل JSON، كما أن وقت الانتهاء ومنطقة التشفير مُضمَّنان في المواصفة نفسها.
2. تنسيق السلك (Wire Format)
expire . cid . plain . secure . signature| الحقل | النوع | الترميز | ملاحظات |
|---|---|---|---|
وقت الانتهاء | uint64 | سلسلة عشرية | Unixtime (بالثواني) |
CID | uint64 | سلسلة ست عشرية | معرّف الشهادة |
بيانات نصية عادية | Binary | Base64Url (بدون حشو) | بيانات عامة |
بيانات مشفرة | Binary | Base64Url (بدون حشو) | بيانات مشفّرة |
التوقيع | Binary | Base64Url (بدون حشو) | توقيع |
2.1. مواصفات الحقول التفصيلية
وقت الانتهاء : uint64 (Unix Time)
- يُعبَّر عن وقت انتهاء صلاحية الرمز بعدد صحيح غير موقَّع 64-بت بوحدة الثواني (Seconds).
- لا يُسمح إلا بأرقام عشرية خالصة. وجود إشارة أو مسافة أو فاصل يُعدّ خطأً في التنسيق.
CID : Hex (uint64)
- معرّف الشهادة (Certificate ID) المستخدم في التحقق من الرمز.
- لا يُسمح إلا بأرقام ست عشرية خالصة، ولا تُستخدم البادئة
0x.
بيانات نصية عادية : Base64Url (Binary)
- يحتوي على البيانات المُعلنة للعميل. يدعم البيانات الثنائية إضافةً إلى النصوص، ويمكن للعميل فكّ ترميزها والاطلاع عليها.
- غير مشفّر. يجب ألا توضع فيه أي قيم حساسة.
بيانات مشفرة : Base64Url (Binary)
- يحتوي على البيانات المخفية عن العميل. يكون مشفّراً بخوارزمية التشفير المحددة في الشهادة، فلا يستطيع أي عميل لا يملك الشهادة فكّ تشفير محتواه.
- بنيته الداخلية هي
IV(96bit) + النص المشفّر، ويُولَّد IV جديد في كل عملية تشفير.
التوقيع : Base64Url (Binary)
- بيانات التوقيع للتحقق من عدم تعديل الرمز أو تزويره. تُنشأ بتوقيع الحقول السابقة بخوارزمية التوقيع الخاصة بالشهادة.
- الرمز الذي يفشل في التحقق من توقيعه يجب ألا يُوثَق بأي حقل من حقوله.
3. القواعد المعيارية (Canonical Rules)
لكي يفسّر العملاء المكتوبون بلغات مختلفة الرمز نفسه بالطريقة نفسها، يجب ألا تختلف القواعد التالية من تنفيذ إلى آخر. التنفيذ المرجعي هو Rust (dat-rust)، وجميع التنفيذات الأخرى مضبوطة على هذه القواعد.
3.1. تحليل الحقول الرقمية
يُفسَّر كل من expire وcid بصرامة. جميع المدخلات التالية تُرفض باعتبارها أخطاء تنسيق.
| مثال الإدخال | النتيجة | السبب |
|---|---|---|
100 | يُقبل | عشري خالص |
007 | يُقبل | الأصفار البادئة مسموحة |
+100 | يُرفض | لا يُسمح بالإشارة |
-1 | يُرفض | لا يُسمح بالإشارة |
" 100 " | يُرفض | لا يُسمح بالمسافات |
1_0 | يُرفض | لا يُسمح بالفواصل |
0x10 | يُرفض | لا يُسمح بالبادئة |
zzzz | يُرفض | ليس رقماً |
"" | يُرفض | سلسلة فارغة |
18446744073709551616 | يُرفض | يتجاوز نطاق uint64 |
لماذا يجب أن تكون الصرامة مطلوبة
المحلّل المتساهل قد يحوّل -1 إلى القيمة العظمى لـ uint64 فيُنتج رمزاً لا ينتهي عملياً، أو يحوّل القيم غير الرقمية بصمت إلى 0. وإذا اختلف مقدار التساهل بين التنفيذات، فسيجتاز الرمز نفسه التحقق في جهة ويُرفض في أخرى، فينكسر التشغيل البيني.
3.2. تحديد انتهاء الصلاحية
حدود الانتهاء تختلف بين رمز DAT والشهادة. لا تخلط بينهما.
| الهدف | شرط الصلاحية | عند لحظة الانتهاء بالضبط (expire == now) |
|---|---|---|
| رمز DAT | expire > now | يُرفض باعتباره منتهياً |
| الشهادة | expire >= now | لا يزال صالحاً |
يصبح الرمز باطلاً فور بلوغ وقت الانتهاء، بينما تظل الشهادة صالحة حتى تلك اللحظة. والسبب أن الشهادة يجب أن تعيش نبضة واحدة أطول من الرمز حتى يمكن التحقق من الرموز الصادرة عند الحدّ.
3.3. حمولة secure الفارغة
إذا لم تكن هناك بيانات لتشفيرها، يكون secure سلسلة فارغة.
encrypt(إدخال فارغ)← إخراج فارغ (لا يُضاف IV ولا وسم GCM)decrypt(إدخال فارغ)← إخراج فارغ- إذا لم يكن فارغاً وكان طوله أقل من أو يساوي طول IV (12 بايت) فهذا خطأ في فك التشفير.
1893456000.1a.SGVsbG8..T3RoZXItc2lnbmF0dXJl
↑ رمز سليم يكون فيه موضع secure فارغاً4. الإصدار والتحقق
4.1. إجراءات الإصدار
- يختار المدير شهادة قابلة للإصدار (issuable) من بين الشهادات التي يملكها.
- يحسب
expire = now + dat_ttl_seconds. - يرمّز
plainبترميز Base64Url، ويشفّرsecureثم يرمّزه بترميز Base64Url. - يوقّع السلسلة
expire.cid.plain.secureويلحق التوقيع بوصفه الحقل الأخير.
4.2. إجراءات التحقق
- يُقسَّم الرمز إلى 5 حقول بالنقطة (
.). إذا اختلف عدد الحقول فهذا خطأ في التنسيق. - يُفحص
expire. الرمز المنتهي يُرفض قبل التحقق من التوقيع. - يُبحث عن الشهادة عبر
cid. إذا لم توجد فالتحقق غير ممكن. - يُتحقق من التوقيع على المقطع
expire.cid.plain.secure. - لا يُفكّ تشفير
secureإلا بعد نجاح التحقق.
لا توثق بأي قيمة قبل التحقق من التوقيع
تقدّم بعض التنفيذات واجهة برمجية لاستخراج الحقول دون التحقق من التوقيع (من فئة parse without verify). هذه القيم خاضعة بالكامل لتلاعب المهاجم، ويجب استخدامها لأغراض التسجيل والتصحيح فقط.
5. المقارنة مع JWT
يتشارك DAT وJWT (JSON Web Token) في بنية الرمز المقسَّمة بنقاط (.) وأسلوب التحقق عبر التوقيع، غير أن ثمة فوارق جوهرية في التصميم الداخلي على النحو الآتي.
5.1. مقارنة الفروق البنيوية
بنية JWT
header body signature Base64Url (JSON String) Base64Url (JSON String) Base64Url (Binary) بنية DAT
وقت الانتهاء CID بيانات نصية عادية بيانات مشفرة التوقيع Unixtime (uint64) Hex (uint64) Base64Url (Binary) Base64Url (Encrypt Binary) Base64Url (Binary)
5.2. الفروق الجوهرية
- تخفيف الحجم بالاعتماد على Binary: يتعامل JWT مع الترويسة (Header) والجسم (Body) على شكل نصوص JSON، بينما يتعامل DAT مباشرةً مع البيانات الثنائية (Binary)، مما يُحسِّن حجم البيانات ويرفع كفاءة التحليل.
- دمج الأمان في البنية (حقل
بيانات مشفرة): يكشف JWT عن حمولته (Payload) افتراضياً بنص واضح، فإذا لزم التشفير وجب تطبيق مواصفة منفصلة كـ JWE. في المقابل، يدعم DAT التشفير داخل الرمز ذاته عبر حقلبيانات مشفرة. - فرض قيد وقت الانتهاء: في JWT يُعدّ حقل
exp(Claims) اختيارياً، أما في DAT فإن حقلوقت الانتهاءمفروض في بنية الرمز، مما يجعل التحقق من مدة الصلاحية حتمياً. - لا تفاوض على الخوارزمية: يحمل JWT قيمة
algفي ترويسته، مما يفتح سطح هجوم خلط الخوارزميات. أما DAT فتحدد الشهادة الخوارزمية، ولا يتضمن الرمز أي معلومات عنها.