Update: 2026-08-03 11:52:03
This commit is contained in:
@@ -310,3 +310,52 @@ function maskPhone(?string $phone): ?string
|
||||
$tail = substr($d, -2);
|
||||
return $head . str_repeat('*', $len - 5) . $tail;
|
||||
}
|
||||
|
||||
/**
|
||||
* عنوان العميل الحقيقي خلف الوسطاء.
|
||||
*
|
||||
* سلسلة الطلب: العميل ← nginx المضيف ← nginx الحاوية ← php-fpm، فيصل
|
||||
* REMOTE_ADDR دائماً كعنوان الوسيط. الاعتماد عليه وحده جعل RateLimiter يضع
|
||||
* كل المستخدمين في دلو واحد، فمحاولات دخول فاشلة من عميل واحد تحجب الجميع.
|
||||
*
|
||||
* X-Forwarded-For قابل للتزوير من العميل، لذا لا نثق به إلا إذا كان
|
||||
* REMOTE_ADDR نفسه وسيطاً موثوقاً (شبكات خاصة/لوكال). خلاف ذلك نعيد
|
||||
* REMOTE_ADDR كما هو.
|
||||
*/
|
||||
function clientIp(): string
|
||||
{
|
||||
$remote = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
|
||||
|
||||
$isTrustedProxy = $remote !== 'unknown' && (
|
||||
filter_var(
|
||||
$remote,
|
||||
FILTER_VALIDATE_IP,
|
||||
FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
|
||||
) === false
|
||||
);
|
||||
|
||||
if (!$isTrustedProxy) {
|
||||
return $remote;
|
||||
}
|
||||
|
||||
$forwarded = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? '';
|
||||
if ($forwarded === '') {
|
||||
return $remote;
|
||||
}
|
||||
|
||||
// أول عنوان عام في السلسلة هو العميل؛ نتخطّى العناوين الخاصة التي
|
||||
// أضافها الوسطاء.
|
||||
foreach (explode(',', $forwarded) as $candidate) {
|
||||
$candidate = trim($candidate);
|
||||
if ($candidate === '') continue;
|
||||
if (filter_var(
|
||||
$candidate,
|
||||
FILTER_VALIDATE_IP,
|
||||
FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
|
||||
) !== false) {
|
||||
return $candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return $remote;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user