Files
Siro/auth_flow_admin_staff.md
2026-06-12 20:40:40 +03:00

676 lines
41 KiB
Markdown

<div dir="rtl" lang="ar">
# سير عمل تسجيل الدخول في نظام Siro
## توثيق شامل لتدفق المصادقة للمشرفين (Super Admin / Admin) وموظفي خدمة العملاء (Service Staff)
---
## 📋 فهرس المحتويات
1. [نظرة عامة على النظام](#نظرة-عامة-على-النظام)
2. [المكونات الرئيسية](#المكونات-الرئيسية)
3. [سير عمل تسجيل حساب مشرف جديد](#سير-عمل-تسجيل-حساب-مشرف-جديد)
4. [سير عمل تسجيل الدخول (المشرف - siro_admin)](#سير-عمل-تسجيل-الدخول-المشرف---siro_admin)
5. [سير عمل تسجيل الدخول (موظف الخدمة - siro_service)](#سير-عمل-تسجيل-الدخول-موظف-الخدمة---siro_service)
6. [سير عمل إضافة الموظفين من قبل المشرف العام](#سير-عمل-إضافة-الموظفين-من-قبل-المشرف-العام)
7. [سير عمل تفعيل الحسابات المعلقة](#سير-عمل-تفعيل-الحسابات-المعلقة)
8. [مقارنة بين تدفق siro_admin و siro_service](#مقارنة-بين-تدفق-siro_admin-و-siro_service)
9. [الجوانب الأمنية (Security)](#الجوانب-الأمنية-security)
10. [قائمة الإصلاحات الأمنية المُنفَّذة](#قائمة-الإصلاحات-الأمنية-المنفذة)
11. [الإجراءات الموصى بها للتحسين (Recommendations)](#الإجراءات-الموصى-بها-للتحسين-recommendations)
---
## نظرة عامة على النظام
نظام Siro يستخدم بنية متعددة التطبيقات (Multi-App Architecture):
| التطبيق | الدور | ملفات المصادقة |
|---------|-------|-----------------|
| **siro_admin** | المشرفون (Admin / Super Admin) | `siro_admin/lib/views/auth/login_page.dart`, `otp_helper.dart` |
| **siro_service** | موظفو خدمة العملاء | `siro_service/lib/controller/login_controller.dart` |
| **Backend (PHP)** | الخادم المركزي | `backend/Admin/auth/login.php`, `backend/serviceapp/login.php` |
المبدأ الأساسي: **المصادقة متعددة العوامل (MFA)** تعتمد على:
1. **بصمة الجهاز (Fingerprint)** — يتم إنشاؤها في التطبيق وإرسالها مع كل طلب
2. **كلمة المرور** — مشفرة باستخدام `password_hash`
3. **OTP عبر WhatsApp** — للتحقق الإضافي (للمشرفين حصراً)
4. **JWT** — التوكن النهائي للوصول
---
## المكونات الرئيسية
### تطبيق siro_admin (المشرفون)
| الملف | المسار | الوظيفة |
|-------|--------|---------|
| `login_page.dart` | `siro_admin/lib/views/auth/` | واجهة تسجيل الدخول (كلمة مرور + هاتف اختياري) |
| `register_page.dart` | `siro_admin/lib/views/auth/` | واجهة طلب حساب مشرف جديد |
| `otp_helper.dart` | `siro_admin/lib/controller/auth/` | منطق OTP وجدولة إعادة الدخول (Auto Login) |
| `register_controller.dart` | `siro_admin/lib/controller/auth/` | منطق التسجيل |
### تطبيق siro_service (خدمة العملاء)
| الملف | المسار | الوظيفة |
|-------|--------|---------|
| `login_controller.dart` | `siro_service/lib/controller/` | منطق تسجيل الدخول مع OTP |
| (لا يوجد register) | | التسجيل يتم عبر `backend/serviceapp/register.php` أو عبر `add.php` |
### الباك إند (PHP)
| الملف | المسار | الوظيفة |
|-------|--------|---------|
| `login.php` | `backend/Admin/auth/` | تسجيل دخول المشرف (الخطوة الأولى) |
| `verify_login.php` | `backend/Admin/auth/` | التحقق من OTP للمشرف (الخطوة الثانية) |
| `register.php` | `backend/Admin/auth/` | تسجيل مشرف جديد |
| `login.php` | `backend/serviceapp/` | تسجيل دخول موظف الخدمة |
| `register.php` | `backend/serviceapp/` | تسجيل موظف خدمة جديد |
| `add.php` | `backend/Admin/Staff/` | إضافة موظف/مشرف من قبل المشرف العام |
| `pending.php` | `backend/Admin/Staff/` | جلب الحسابات المعلقة |
| `activate.php` | `backend/Admin/Staff/` | تفعيل الحسابات المعلقة |
| `jwtService.php` | `backend/Admin/jwtService.php` | إصدار JWT لخدمة العملاء (قديم) |
| `JwtService.php` | `backend/core/Auth/` | خدمة JWT الأساسية مع Authentication |
---
## سير عمل تسجيل حساب مشرف جديد
### 📍 يبدأ من تطبيق siro_admin ← `register_page.dart`
```
[المستخدم] [التطبيق (Flutter)] [الباك إند (PHP)] [قاعدة البيانات]
| | | |
|── يدخل الاسم، الهاتف، | | |
| كلمة المرور | | |
|─────────────────────────────>| | |
| | | |
| |── قراءة بصمة الجهاز (fingerprint) | |
| | من `box.read('fingerprint')` | |
| | | |
| |── POST `/Admin/auth/register.php` | |
| | مع: name, phone, password, fingerprint | |
| |──────────────────────────────────────────>| |
| | | |
| | |── التحقق من القائمة البيضاء |
| | | `AUTHORIZED_ADMIN_PHONES` |
| | | في متغيرات البيئة (.env) |
| | | |
| | |── التحقق من التكرار: |
| | | phone OR fingerprint_hash |
| | | |
| | |── تشفير البيانات: |
| | | • name ← encryptData() |
| | | • phone ← encryptData() |
| | | • fingerprint ← encrypt() |
| | | • fingerprint_hash = |
| | | SHA-256(fingerprint) |
| | | • password ← password_hash |
| | | |
| | |── توليد UUID آمن: |
| | | bin2hex(random_bytes(16)) |
| | | |
| | |── INSERT INTO adminUser |
| | | status = 'pending' |
| | | role = 'admin' |
| | |─────────────────────────────>| (id, fingerprint, fingerprint_hash,
| | | | name, phone, password, role,
| | | | status='pending', created_at)
| | | |
| |<── { status: "pending", message: "..." } | |
| | | |
|<── رسالة "تم تقديم الطلب" | | |
```
### ملاحظات أمنية حول التسجيل:
- ✅ القائمة البيضاء (`AUTHORIZED_ADMIN_PHONES`) تمنع أي شخص من التسجيل دون إذن مسبق
- ✅ الاسم والهاتف والبصمة مشفرة في قاعدة البيانات
- ✅ بصمة الجهاز محولة إلى SHA-256 Hash للبحث السريع
-**`bin2hex(random_bytes(16))`** لتوليد UUID آمن — تم إصلاحه من `rand()`
- 🔴 الحساب ينشأ بحالة `pending` ولا يمكنه الدخول حتى يتم تفعيله يدوياً
---
## سير عمل تسجيل الدخول (المشرف - siro_admin)
### 📍 يبدأ من `login_page.dart` ← `OtpHelper.loginWithPassword()`
#### الخطوة الأولى: إرسال طلب الدخول
```
[المستخدم] [otp_helper.dart] [login.php (Backend)] [Redis / DB]
| | | |
|── يدخل كلمة المرور | | |
| (ورقم الهاتف لأول | | |
| مرة) | | |
|──────────────────────>| | |
| | | |
| |── POST /Admin/auth/login.php | |
| | payload: fingerprint, | |
| | password, phone (اختياري), | |
| | aud (اختياري), is_renewal | |
| |──────────────────────────────────>| |
| | | |
| | |── Rate Limiting: |
| | | 5 محاولات/دقيقة لكل IP |
| | | |
| | |── البحث بـ fingerprint_hash |
| | | (SHA-256 للبصمة) |
| | | |
| | [إذا لم يوجد بالبصمة والهاتف موجود] |
| | |── البحث بالهاتف المشفر |
| | | (لأول مرة أو جهاز جديد) |
| | | |
| | |── التحقق من status: |
| | | • pending → رفض مع رسالة |
| | | • suspended → رفض |
| | | • rejected → رفض |
| | | • active → متابعة |
| | | |
| | |── التحقق من كلمة المرور: |
| | | password_verify(password) |
| | | |
```
#### التفرع حسب `is_renewal`:
```
|
┌───────────────┴───────────────┐
| |
is_renewal=1 is_renewal=0 أو missing
(إعادة دخول تلقائي) (تسجيل دخول يدوي)
| |
| ├── توليد OTP عشوائي
| | (100000-999999) ← 6 أرقام
| |
| ├── فك تشفير رقم الهاتف
| | ← إرسال OTP عبر WhatsApp
| |
| ├── حفظ OTP مشفراً:
| | `token_verification_admin`
| | (phone مشفر، token مشفر،
| | expiration 10 دقائق)
| |
| └── رد: { status: "otp_required",
| phone: masked }
|
├── إلغاء التوكن القديم من Redis
| (Token Revocation)
|
├── توليد JWT جديد:
| generateAccessToken(id, role, aud, fingerprint)
|
└── رد مباشر: { jwt, admin, expires_in }
```
### الخطوة الثانية (عند طلب OTP): التحقق ← `verify_login.php`
```
[otp_helper.dart] [verify_login.php] [DB / Redis]
| | |
|── POST /Admin/auth/ | |
| verify_login.php | |
| payload: otp, | |
| fingerprint, phone | |
|────────────────────────────>| |
| | |
| |── Rate Limiting: |
| | 3 محاولات OTP/5 دقائق لكل IP |
| | |
| |── البحث بالـ fingerprint_hash |
| | من جدول adminUser |
| | |
| |── تشفير OTP المدخل |
| | encryptData(otp) |
| | |
| |── البحث في token_verification: |
| | phone_number = encryptedPhone |
| | AND token = encryptedOtp |
| | AND expiration >= NOW() |
| | |
| [غير صالح أو منتهي] | |
|<── "رمز التحقق غير صالح" | |
| | |
| [صالح] | |
| |── حذف OTP (استخدام لمرة واحدة) |
| | DELETE FROM token_verification |
| | |
| |── إلغاء التوكن القديم من Redis |
| | |
| |── توليد JWT جديد: |
| | generateAccessToken(id, role, |
| | aud, fingerprint) |
| | |
|<── { jwt, admin, expires_in }| |
| | |
|── حفظ البيانات محلياً: | |
| • JWT ← box.write(jwt) | |
| • admin_id ← box.write | |
| • admin_role ← box.write | |
| • phoneVerified ← true | |
| • admin_password ← حفظ | |
| | |
|── Get.offAll(AdminHomePage())| |
```
### مخطط الحالة الكامل للمشرف (State Machine):
```
┌───────────┐
│ Pending │ ← بعد التسجيل، بحاجة تفعيل
└─────┬─────┘
│ Activate.php (يتطلب JWT مع role=admin)
┌─────────────────┐
│ Active │ ← يمكنه تسجيل الدخول
└────────┬────────┘
┌─────────┴──────────┐
│ │
▼ ▼
┌───────────┐ ┌───────────┐
│ Suspended │ │ Rejected │
└───────────┘ └───────────┘
```
---
## سير عمل تسجيل الدخول (موظف الخدمة - siro_service)
### 📍 يبدأ من `login_controller.dart` ← `login()`
```
[LoginController] [serviceapp/login.php] [DB / Redis]
| | |
|── قراءة البصمة من | |
| box.read(fingerprint) | |
| | |
|── POST /serviceapp/login.php | |
| payload: fingerprint, | |
| password, email, | |
| aud = "service" | |
|────────────────────────────>| |
| | |
| |── Rate Limiting: |
| | 5 محاولات/دقيقة لكل IP |
| | |
| |── البحث بـ fingerprint_hash |
| | في `users` WHERE user_type |
| | = 'service' |
| | |
| [إذا لم يوجد, والإيميل موجود] |
| |── البحث بالإيميل المشفر |
| | |
| |── التحقق من status: |
| | • pending → "قيد المراجعة" |
| | • suspended → "معلق" |
| | • approved → متابعة |
| | |
| |── التحقق من كلمة المرور |
| | |
| |── فك تشفير البيانات للعرض: |
| | first_name, last_name, |
| | email, phone |
| | |
| |── إدارة التوكنات: |
| | 1. البحث عن توكن موجود في |
| | Redis (active_token) |
| | 2. إذا وجد وصالح ← استخدامه |
| | 3. إذا لم يوجد ← إلغاء القديم |
| | وتوليد جديد |
| | |
| |── توليد HMAC Key: |
| | hmac = hash_hmac(sha256, |
| | userId, SECRET_KEY_HMAC) |
| | |
|<── { message, data, jwt, | |
| hmac, expires_in } | |
| | |
|── إرسال OTP: | |
| POST /auth/otp/request.php | |
| payload: receiver=phone, | |
| user_type='service' | |
| | |
|── عرض Dialog OTP | |
| | |
|── التحقق من OTP: | |
| POST /auth/otp/verify.php | |
| payload: phone_number, | |
| token_code, user_type | |
| | |
|── حفظ JWT + HMAC محلياً | |
| | |
|── Get.offAll(Main()) | |
```
---
## سير عمل إضافة الموظفين من قبل المشرف العام
### 📍 `backend/Admin/Staff/add.php`
يستخدم هذا الملف لإضافة موظفين جدد من قبل المشرف العام (Super Admin أو Admin فقط).
```
┌─────────────────────────────────────┐
│ add.php │
│ │
│ ✅ JWT Authentication: │
│ $jwtService = new JwtService │
│ $auth = $jwtService->authenticate│
│ $authRole = $auth->role │
│ if role ≠ super_admin || admin → │
│ رفض الطلب │
└──────────────────┬──────────────────┘
──────────────┼──────────────
role='admin' │ role='service'
┌─────────────────────────┴──────────────────────────┐
▼ ▼
┌────────────────┐ ┌──────────────────┐
│ adminUser │ │ users │
│ table │ │ table │
├────────────────┤ ├──────────────────┤
│ id (bin2hex) │ │ id (bin2hex) │
│ fingerprint │ │ fingerprint │
│ fingerprint_ │ │ fingerprint_hash │
│ hash │ │ phone (مشفر) │
│ name (مشفر) │ │ email (مشفر) │
│ phone (مشفر) │ │ gender │
│ password │ │ password │
│ role 'admin' │ │ birthdate │
│ created_at │ │ user_type │
└────────────────┘ │ 'service' │
│ first_name (مشفر) │
│ last_name │
│ site │
│ created_at │
└──────────────────┘
```
### 🔐 آلية التحقق في add.php (بعد الإصلاح):
```php
$jwtService = new JwtService($redis);
$auth = $jwtService->authenticate(); // يقرأ Bearer token من Authorization header
$authRole = $auth->role ?? ''; // يستخرج الدور من JWT payload
if ($authRole !== 'super_admin' && $authRole !== 'admin') {
jsonError("غير مصرح لك. فقط المشرفون يمكنهم إضافة موظفين.");
exit;
}
```
### نقاط مهمة في add.php:
-`bin2hex(random_bytes(16))` لتوليد UUID آمن
- ✅ البيانات الحساسة مشفرة قبل الحفظ
-`fingerprint` اختياري — يمكن إضافة موظف بدون بصمة مسبقة
-**التحقق من JWT Authentication** مطلوب قبل الإضافة
---
## سير عمل تفعيل الحسابات المعلقة
### 📍 `pending.php` → `activate.php`
#### استعراض الحسابات المعلقة:
```
[pending.php] [قاعدة البيانات]
│ │
│── SELECT FROM adminUser │
│ WHERE status='pending' │
│ │
│── SELECT FROM users │
│ WHERE status='pending' │
│ AND user_type='service' │
│ │
│── فك تشفير الأسماء والأرقام │
│ │
│── دمج النتائج (array_merge) │
│ │
│<── { data: [all_pending] } │
```
#### تفعيل حساب:
```
[activate.php] [قاعدة البيانات]
│ │
│── التحقق من JWT: │
│ $jwtService = new JwtService │
│ $auth = $jwtService->authenticate│
│ $authRole = $auth->role │
│ if ≠ super_admin && ≠ admin → │
│ رفض │
│ │
│── POST مع: user_id, type │
│ │
│ type='admin': │
│ UPDATE adminUser │
│ SET status='active' │
│ WHERE id=user_id │
│ AND status='pending' │
│ │
│ type='service': │
│ UPDATE users │
│ SET status='approved' │
│ WHERE id=user_id │
│ AND status='pending' │
│ AND user_type='service' │
│ │
│<── "تم التفعيل بنجاح" │
```
### 🔐 آلية التحقق في activate.php (بعد الإصلاح):
```php
$jwtService = new JwtService($redis);
$auth = $jwtService->authenticate();
$authRole = $auth->role ?? '';
if ($authRole !== 'super_admin' && $authRole !== 'admin') {
jsonError("غير مصرح لك. فقط المشرف العام يمكنه تفعيل الحسابات.");
exit;
}
```
---
## مقارنة بين تدفق siro_admin و siro_service
| الخاصية | siro_admin (المشرف) | siro_service (خدمة العملاء) |
|---------|---------------------|-----------------------------|
| **جدول البيانات** | `adminUser` | `users` |
| **مفتاح البحث** | بصمة الجهاز ← الهاتف | بصمة الجهاز ← الإيميل |
| **آلية OTP** | OTP عبر WhatsApp كخطوة قبل JWT | JWT يصدر أولاً ثم OTP كخطوة تأكيد |
| **Auto Login** | Yes (is_renewal=1) + JWT غير منتهي | Yes (كلمة مرور مخزنة) |
| **إلغاء التوكن القديم** | قبل إصدار الجديد (Redis) | قبل إصدار الجديد (Redis) |
| **عدد أرقام OTP** | 6 أرقام (مُحسَّن) | لا يوجد OTP مدمج بالـ login |
| **HMAC Key** | غير مستخدم | يستخدم للتوافق مع CRUD |
| **نوع التسجيل** | تسجيل ذاتي + قائمة بيضاء | إضافة يدوية أو تسجيل ذاتي |
| **الحالة عند الإنشاء** | `pending` | `pending` / `active` |
---
## الجوانب الأمنية (Security)
### ✅ نقاط القوة
1. **تشفير البيانات الحساسة** — جميع PII (الاسم، الهاتف، الإيميل، البصمة) مشفرة في قاعدة البيانات بواسطة `encryptData()`
2. **بصمة الجهاز (Fingerprint)** — ربط الحساب بجهاز معين يمنع الوصول من أجهزة غير معروفة
3. **إلغاء التوكن (Token Revocation)** — التوكن القديم يُلغى قبل إصدار الجديد عبر Redis
4. **OTP لمدة محدودة** — صلاحية 10 دقائق فقط للرمز
5. **استخدام لمرة واحدة** — OTP يُحذف بعد التحقق
6. **القائمة البيضاء** — التسجيل الذاتي مقيد بأرقام مصرح بها من `.env`
7. **Hash للبصمة**`SHA-256` للبحث السريع دون تخزين البصمة كما هي
8. **قناع رقم الهاتف** — في الاستجابة، يظهر فقط `07XX***XXX`
9. **UUID آمن**`bin2hex(random_bytes(16))` بدلاً من `rand()` (تم الإصلاح)
10. **JWT Authentication** — لملفي add.php و activate.php (تم الإصلاح)
11. **Rate Limiting** — على login و OTP (تم الإضافة)
### ✅ الإصلاحات الأمنية المُنفَّذة
| # | الثغرة | الملف | الحالة |
|---|--------|-------|--------|
| 1 | `rand()` لتوليد ID (ضعيف) | `Admin/auth/register.php` | ✅ تم الاستبدال بـ `bin2hex(random_bytes(16))` |
| 2 | التحقق من الصلاحيات معلق (Commented Out) | `Admin/Staff/add.php` | ✅ تم التفعيل عبر `JwtService::authenticate()` |
| 3 | لا يوجد تحقق من صلاحية المشرف العام | `Admin/Staff/activate.php` | ✅ تم إضافة JWT + التحقق من role |
| 4 | لا يوجد Rate Limiting على login | `Admin/auth/login.php` | ✅ تم الإضافة (5 محاولات/دقيقة) |
| 5 | لا يوجد Rate Limiting على login | `serviceapp/login.php` | ✅ تم الإضافة (5 محاولات/دقيقة) |
| 6 | لا يوجد Rate Limiting على OTP | `Admin/auth/verify_login.php` | ✅ تم الإضافة (3 محاولات/5 دقائق) |
| 7 | OTP 5 أرقام (ضعيف) | `Admin/auth/login.php` | ✅ تم الرفع إلى 6 أرقام (100000-999999) |
### ❌ الثغرات المتبقية (لم تُعالَج بعد)
| الثغرة | الموقع | التأثير |
|--------|--------|---------|
| **كلمات مرور plain text (قديمة)** | `Admin/jwtService.php` (السطر 49) | دعم كلمات المرور غير المشفرة للتوافق القديم |
| **JWT Service مكرر** | `Admin/jwtService.php` و `core/Auth/JwtService.php` | يوجد ملفان باسم JwtService بوظائف مختلفة |
| **Auto Login بدون OTP** | `Admin/auth/login.php` مع `is_renewal=1` | إذا سُرقت البصمة وكلمة المرور، يمكن الدخول بدون OTP |
| **كشف البصمة في الأخطاء** | `otp_helper.dart` | لا يوجد تدقيق كافٍ في التقاط الأخطاء |
---
## قائمة الإصلاحات الأمنية المُنفَّذة
### 1. ✅ `Admin/auth/register.php` — استبدال ID الضعيف
**قبل الإصلاح:**
```php
$uniqueId = rand(100000000, 999999999); // غير آمن، قد يتكرر
```
**بعد الإصلاح:**
```php
$uniqueId = bin2hex(random_bytes(16)); // UUID آمن (32 حرف hex عشوائي)
```
### 2. ✅ `Admin/Staff/add.php` — تفعيل التحقق من الصلاحيات
**قبل الإصلاح:**
```php
// التحقق معلق (Commented Out)
// $auth = JwtService::authenticate($redis);
// if ($auth['role'] !== 'super_admin' && $auth['role'] !== 'admin') { ... }
```
**بعد الإصلاح:**
```php
$jwtService = new JwtService($redis);
$auth = $jwtService->authenticate();
$authRole = $auth->role ?? '';
if ($authRole !== 'super_admin' && $authRole !== 'admin') {
jsonError("غير مصرح لك. فقط المشرفون يمكنهم إضافة موظفين.");
exit;
}
```
### 3. ✅ `Admin/Staff/activate.php` — إضافة JWT Authentication
**قبل الإصلاح:**
```php
// يجب التأكد من صلاحيات الـ Super Admin هنا
// (عادةً يتم التحقق من التوكن أو الـ Session)
```
**بعد الإصلاح:**
```php
$jwtService = new JwtService($redis);
$auth = $jwtService->authenticate();
$authRole = $auth->role ?? '';
if ($authRole !== 'super_admin' && $authRole !== 'admin') {
jsonError("غير مصرح لك. فقط المشرف العام يمكنه تفعيل الحسابات.");
exit;
}
```
### 4. ✅ `Admin/auth/login.php` — إضافة Rate Limiting + رفع OTP إلى 6 أرقام
```php
// Rate Limiting قبل بدء المعالجة
$rateLimiter = new RateLimiter($redis);
$rateLimiter->enforce(RateLimiter::identifier(), 'login');
// ... لاحقاً عند توليد OTP ...
$otp = rand(100000, 999999); // 6 أرقام بدلاً من 5
```
### 5. ✅ `serviceapp/login.php` — إضافة Rate Limiting
```php
$rateLimiter = new RateLimiter($redis);
$rateLimiter->enforce(RateLimiter::identifier(), 'login');
```
### 6. ✅ `Admin/auth/verify_login.php` — إضافة Rate Limiting لـ OTP
```php
$rateLimiter = new RateLimiter($redis);
$rateLimiter->enforce(RateLimiter::identifier(), 'otp'); // 3 محاولات/5 دقائق
```
---
## خلاصة
```mermaid
graph TD
subgraph "siro_admin (تطبيق المشرف)"
A[Login Page] --> B[OtpHelper.loginWithPassword]
B --> C{is_renewal?}
C -->|نعم| D[JWT مباشر]
C -->|لا| E[طلب OTP - 6 أرقام]
E --> F[Verify OTP - Rate Limited]
F --> G[JWT نهائي]
end
subgraph "Backend PHP - مؤمَّن"
H[Admin/auth/login.php] --> RL1[Rate Limiter ✅]
RL1 --> I[بحث بالبصمة/هاتف]
I --> J[فحص الحالة]
J --> K[التحقق من كلمة المرور]
K --> L[توليد OTP 6-digits ✅ / JWT]
M[verify_login.php] --> RL2[Rate Limiter (OTP) ✅]
RL2 --> N[التحقق من OTP]
N --> O[إصدار JWT]
P[add.php] --> AUTH1[JWT Authentication ✅]
Q[activate.php] --> AUTH2[JWT Authentication ✅]
end
subgraph "siro_service (تطبيق الخدمة)"
R[LoginController.login] --> S[serviceapp/login.php]
S --> RL3[Rate Limiter ✅]
RL3 --> T[JWT + HMAC]
T --> U[OTP للتأكيد]
U --> V[تسجيل دخول نهائي]
end
B --> H
F --> M
R --> S
```
النظام مبني على أساس أمني قوي مع تشفير متعدد الطبقات. تم إصلاح 7 ثغرات أمنية:
1. **UUID آمن** بدلاً من `rand()` في تسجيل المشرفين
2. **JWT Authentication** في add.php — يمنع أي شخص غير مصرح له من إضافة موظفين
3. **JWT Authentication** في activate.php — يضمن أن المشرف العام فقط هو من يمكنه التفعيل
4. **Rate Limiting** (5 محاولات/دقيقة) على login.php للمشرفين
5. **Rate Limiting** (5 محاولات/دقيقة) على login.php لخدمة العملاء
6. **Rate Limiting** (3 محاولات/5 دقائق) على verify_login.php (OTP)
7. **رفع OTP إلى 6 أرقام** لزيادة صعوبة التخمين
---
> **تاريخ التوثيق:** 12 يونيو 2026
> **آخر تحديث:** 12 يونيو 2026 (تم تنفيذ الإصلاحات)
> **الإصدار:** 2.0
> **المراجعة القادمة:** —
> **المعنيون:** فريق التطوير — Siro
</div>