Update codebase
This commit is contained in:
@@ -156,7 +156,9 @@ class JwtService
|
||||
|
||||
// 3. Issuer (Only check if configured)
|
||||
if (!empty($this->issuer) && ($decoded->iss ?? '') !== $this->issuer) {
|
||||
self::abort(401, 'Invalid token issuer: expected ' . $this->issuer . ' but got ' . ($decoded->iss ?? 'none'));
|
||||
// التفاصيل في اللوج فقط — لا تُكشف في الرد.
|
||||
error_log('[SECURITY] Issuer mismatch | expected: ' . $this->issuer . ' | got: ' . ($decoded->iss ?? 'none'));
|
||||
self::abort(401, 'Invalid token issuer');
|
||||
}
|
||||
|
||||
// 3.1 App Signature Verification (Service Only)
|
||||
@@ -228,8 +230,15 @@ class JwtService
|
||||
}
|
||||
|
||||
if ($fpInToken === null || $fpHeader === null) {
|
||||
$allHeaders = json_encode(getallheaders());
|
||||
error_log("[SECURITY] Fingerprint missing | user: $userId | fpInToken: " . ($fpInToken ?? 'NULL') . " | fpHeader: " . ($fpHeader ?? 'NULL') . " | Headers: $allHeaders");
|
||||
// ملاحظة: ممنوع تسجيل الهيدرز كاملة — كانت تُسرّب الـ
|
||||
// Authorization: Bearer <token> بالنص الصريح إلى error_log.
|
||||
// نسجّل فقط أيّ الطرفين ناقص، دون أي قيمة.
|
||||
error_log(sprintf(
|
||||
"[SECURITY] Fingerprint missing | user: %s | inToken: %s | inHeader: %s",
|
||||
$userId,
|
||||
$fpInToken === null ? 'no' : 'yes',
|
||||
$fpHeader === null ? 'no' : 'yes'
|
||||
));
|
||||
self::abort(403, 'Device verification required');
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ class RateLimiter
|
||||
// حدود مختلفة لكل نوع endpoint
|
||||
private const LIMITS = [
|
||||
'login' => ['requests' => 5, 'window' => 60], // 5 محاولات / دقيقة
|
||||
'tester_login' => ['requests' => 3, 'window' => 60], // 3 محاولات / دقيقة
|
||||
'tester_login' => ['requests' => 30, 'window' => 60], // 30 محاولة / دقيقة (مراجعو المتاجر يكرّرون الدخول بسرعة)
|
||||
'otp' => ['requests' => 3, 'window' => 300], // 3 محاولات / 5 دقائق
|
||||
'register' => ['requests' => 3, 'window' => 3600], // 3 محاولات / ساعة
|
||||
'api' => ['requests' => 180, 'window' => 60], // 180 طلب / دقيقة (الإنتاج الرسمى)
|
||||
@@ -79,7 +79,15 @@ class RateLimiter
|
||||
// ── بناء معرّف المستخدم ────────────────────────────────────
|
||||
public static function identifier(?string $userId = null): string
|
||||
{
|
||||
$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
|
||||
// كان REMOTE_ADDR وحده، وهو خلف دوكر دائماً عنوان الوسيط نفسه
|
||||
// (172.24.0.1) — فيتشارك كل المستخدمين دلواً واحداً، ومحاولات دخول
|
||||
// فاشلة من عميل واحد تحجب الجميع بـ 429 (ظهر ذلك في سجل الإنتاج).
|
||||
// clientIp() تستخرج العميل الحقيقي من X-Forwarded-For ولا تثق به
|
||||
// إلا إذا كان REMOTE_ADDR وسيطاً موثوقاً.
|
||||
$ip = function_exists('clientIp')
|
||||
? clientIp()
|
||||
: ($_SERVER['REMOTE_ADDR'] ?? 'unknown');
|
||||
|
||||
return $userId ? "{$ip}:{$userId}" : $ip;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user