مقابله با جعل آدرس IP در برنامههای ASP.NET Core پشت سرور پروکسی معکوس Nginx
نویسنده: وحید نصیری
تاریخ: ۱۴۰۵/۰۶/۱۸ ۰۹:۱۵
آدرس: www.dntips.ir
چکیده: در معماریهای وب متداول، سرویس برنامههای کاربردی داتنت (ASP.NET Core Kestrel) در لایه داخلی شبکه و پشت یک پروکسی معکوس مانند Nginx قرار میگیرد. در چنین چینشهایی، تشخیص صحیح آدرس IP واقعی کلاینت (Client IP) برای ثبت وقایع، محدودسازی نرخ تراکنشها (Rate Limiting)، اعتبارسنجیهای امنیتی و کشف حملات از اهمیت حیاتی برخوردار است. با این حال، استفاده نادرست از هدرهای HTTP نظیرX-Forwarded-ForوX-Real-IPبدون اعتبارسنجی مرز اعتماد شبکه، منجر به آسیبپذیری جعل هدر (Header Spoofing / IP Spoofing) میشود. مهاجمان با ارسال هدرهای ساختگی (مانند آدرسهای خصوصی نظیر10.0.0.1) هویت واقعی خود را پنهان کرده و سدهای نظارتی و امنیتی نرمافزار را دور میزنند. این مقاله با تحلیل ریشهای این آسیبپذیری در تعامل Nginx و Kestrel، خطرات پارس دستی هدرها در کدهای #C را بررسی کرده و راهکار استاندارد و دومرحلهای اصلاح پیکربندی Nginx و بهکارگیری میدلویر رسمیForwardedHeadersMiddlewareدر داتنت را تشریح میکند.
127.0.0.1 یا آدرس سوکت یونیکس) برقرار میشود. در نتیجه، ویژگی پیشفرض HttpContext.Connection.RemoteIpAddress آدرس پروکسی داخلی را نمایش میدهد، نه کلاینت بیرونی را.X-Forwarded-* استفاده میشود. چالش اصلی زمانی رخ میدهد که توسعهدهنده بدون در نظر گرفتن رفتار پیشفرض Nginx و سناریوهای مخرب، مقدار این هدرها را به عنوان منبع موثق هویت شبکه در نظر بگیرد. کلاینت مخرب میتواند با ارسال بستههای HTTP که حاوی مقادیر دلخواه در هدرهای X-Forwarded-For یا X-Real-IP هستند، رفتار برنامه را دستکاری کند.proxy_set_header با متغیر $proxy_add_x_forwarded_forproxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
$proxy_add_x_forwarded_for مقدار قبلی هدر X-Forwarded-For موجود در درخواست کلاینت را حفظ کرده و IP سوکت ورودی ($remote_addr) را به انتهای آن (با کاما) الحاق میکند.X-Forwarded-For: 10.0.0.1
203.0.113.50) را به انتهای آن اضافه میکند:X-Forwarded-For: 10.0.0.1, 203.0.113.50
Public IP) را بیابند. اگر مهاجم هدرهای چندگانه یا آدرسهای خصوصی تزریق کرده باشد و متد نتواند آدرس عمومی را برگزیند، در حالت Fallback به اولین عنصر لیست (چپترین ورودی که توسط خود مهاجم تزریق شده) اتکا میکند. نتیجه این رخداد، ثبت آدرس جعلی 10.0.0.1 به جای هویت واقعی مهاجم در سیستم لاگ و ابزارهای مانیتورینگ خواهد بود.[ کلاینت / مهاجم ]
│
▼ (درخواست با هدرهای جعلی X-Forwarded-For: 10.0.0.1)
┌────────────────────────────────────────────────────────┐
│ Nginx (Reverse Proxy)
│ - پاکسازی هدرهای قبلی
│ - ست کردن هدر با IP سوکت فیزیکی ($remote_addr)
└────────────────────────────────────────────────────────┘
│
▼ (X-Forwarded-For: 203.0.113.50)
┌────────────────────────────────────────────────────────┐
│ ASP.NET Core (Kestrel)
│ - ForwardedHeadersMiddleware
│ - اعتماد فقط به پروکسی معتبر (127.0.0.1)
│ - ثبت دقیق در HttpContext.Connection.RemoteIpAddress
└────────────────────────────────────────────────────────┘$remote_addr است. این متغیر از روی سوکت TCP استخراج میشود و در لایه پروتکل HTTP قابل جعل نیست.$remote_addr بازنویسی کند:server {
listen 80;
server_name example.com;
location / {
# بازنویسی قطعی با IP سوکت واقعی کلاینت (حذف هدرهای جعلی ورودی)
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
# حفظ متادیتای مورد نیاز پروتکل و دامنه
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:5000;
}
}sudo nginx -t && sudo systemctl reload nginx
UseForwardedHeaders است. این میدلویر هدرهای دریافتی از پروکسیهای معتبر و مشخص را پردازش کرده و مستقیماً مقادیر HttpContext.Connection.RemoteIpAddress و HttpContext.Request.Scheme را به مقادیر واقعی تغییر میدهد. در نتیجه، تمام بخشهای برنامه، لاگرها و کتابخانههای ثالث بدون تغییر کد به آدرس صحیح دسترسی خواهند داشت.Program.cs:using System.Net;
using Microsoft.AspNetCore.HttpOverrides;
var builder = WebApplication.CreateBuilder(args);
// ۱. تنظیم گزینههای هدرهای ارسالی
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
// پاکسازی شبکهها و پروکسیهای پیشفرض
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
// تعیین دقیق مرز اعتماد: تنها Nginx لوکال مجاز به بازنویسی هدرها است
options.KnownProxies.Add(IPAddress.Loopback);
options.KnownProxies.Add(IPAddress.IPv6Loopback);
});
var app = builder.Build();
// ۲. ثبت میدلویر در ابتدای پایپلاین قبل از احراز هویت و لاگینگ
app.UseForwardedHeaders();
app.MapGet("/api/client-ip", (HttpContext context) =>
{
// مقدار RemoteIpAddress به طور خودکار حاوی آدرس واقعی کلاینت خواهد بود
var clientIp = context.Connection.RemoteIpAddress?.ToString();
return Results.Ok(new { ClientIP = clientIp });
});
app.Run();نکته کلیدی در معماری امن: متغیرهایKnownProxiesوKnownNetworksدیواره آتشین میدلویر هستند. اگر بستهای مستقیماً (با دور زدن Nginx) به پورت Kestrel ارسال شود، چون فرستنده آن در لیستKnownProxiesنیست، ASP.NET Core هدرهایX-Forwarded-*را نادیده گرفته و دستکاری رد خواهد شد.
::ffff:192.0.2.1 بازگردانند. اگر متدها یا لاگرهای شما نیاز به استانداردسازی آدرس دارند، استفاده از متد داخلی داتنت توصیه میشود:var rawIp = context.Connection.RemoteIpAddress;
var normalizedIp = rawIp is not null && rawIp.IsIPv4MappedToIPv6
? rawIp.MapToIPv4()
: rawIp;$remote_addr آدرس گرههای CDN را ثبت میکند.ngx_http_realip_module در Nginx است:set_real_ip_from، تنها بازههای IP رسمی سرورهای CDN به عنوان مبدا معتبر معرفی میشوند.CF-Connecting-IP) به عنوان منبع استخراج آدرس واقعی کلاینت معین میگردد.Fail2ban و قوانین فایروال (iptables / nftables) در ابتدای پشته شبکه مسدود کرد:# نمونه مسدودسازی در Nginx deny 203.0.113.50;
$remote_addr جایگزین شوند تا جعل هدر در لایه لبه متوقف شود.ForwardedHeadersMiddleware و تعیین صریح KnownProxies، اطلاعات هویتی درخواست به شکل ایمن و شفاف در چرخه حیات HttpContext در دسترس قرار گیرد.