重新導向至透過要求指定的 URL 的 Web 應用程式,例如 querystring 或表單資料,可能會遭到竄改,以將使用者重新導向至外部惡意 URL。 這項竄改稱為開放式重新導向攻擊。
每當應用程式邏輯重新導向至指定的 URL 時,您必須確認重新導向 URL 尚未遭到竄改。 ASP.NET Core具有內建功能,可協助保護應用程式免于開啟重新導向 (也稱為開放式重新導向) 攻擊。
LocalRedirect
如果指定了非本機 URL,將會擲回例外狀況。 否則,其行為就像 Redirect 一樣。
public IActionResult SomeAction(string redirectUrl)
{
return LocalRedirect(redirectUrl);
}
重新導向之前檢查 URL 是否為本機。
private IActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction(nameof(HomeController.Index), "Home");
}
}
可以藉由以下方法來設定允許存取的 IP 清單:
-中介軟體
-‵ActionFilter
-Razor 頁面 Filter
用逗點
分隔
{
"AllowList": "127.0.0.1;192.168.1.5;::1"
}
自訂 AllowListMiddleware
app.UseMiddleware<AllowListMiddleware>(Configuration["AllowList"]);
public class AllowListMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<AllowListMiddleware> _logger;
private readonly byte[][] _safelist;
public AllowListMiddleware(
RequestDelegate next,
ILogger<AllowListMiddleware> logger,
string safelist)
{
var ips = safelist.Split(';');
_safelist = new byte[ips.Length][];
for (var i = 0; i < ips.Length; i++)
{
_safelist[i] = IPAddress.Parse(ips[i]).GetAddressBytes();
}
_next = next;
_logger = logger;
}
public async Task Invoke(HttpContext context)
{
if (context.Request.Method != HttpMethod.Get.Method)
{
var remoteIp = context.Connection.RemoteIpAddress;
_logger.LogDebug("Request from Remote IP address: {RemoteIp}", remoteIp);
var bytes = remoteIp.GetAddressBytes();
var badIp = true;
foreach (var address in _safelist)
{
if (address.SequenceEqual(bytes))
{
badIp = false;
break;
}
}
if (badIp)
{
_logger.LogWarning(
"禁止這個 IP : {RemoteIp}", remoteIp);
context.Response.StatusCode = (int) HttpStatusCode.Forbidden;
return;
}
}
await _next.Invoke(context);
}
}
如果您想要針對特定 MVC Controller 或 Action 限制 IP,請使用 ActionFilter。
ActionFilterAttribute
public class ClientIpCheckActionFilter : ActionFilterAttribute
{
private readonly ILogger _logger;
private readonly string _safelist;
public ClientIpCheckActionFilter(string safelist, ILogger logger)
{
_safelist = safelist;
_logger = logger;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
var remoteIp = context.HttpContext.Connection.RemoteIpAddress;
_logger.LogDebug("Remote IpAddress: {RemoteIp}", remoteIp);
var ip = _safelist.Split(';');
var badIp = true;
if (remoteIp.IsIPv4MappedToIPv6)
{
remoteIp = remoteIp.MapToIPv4();
}
foreach (var address in ip)
{
var testIp = IPAddress.Parse(address);
if (testIp.Equals(remoteIp))
{
badIp = false;
break;
}
}
if (badIp)
{
_logger.LogWarning("Forbidden Request from IP: {RemoteIp}", remoteIp);
context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
return;
}
base.OnActionExecuting(context);
}
}
Program.cs
services.AddScoped<ClientIpCheckActionFilter>(container =>
{
var loggerFactory = container.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger<ClientIpCheckActionFilter>();
return new ClientIpCheckActionFilter(
Configuration["AllowList"], logger);
});
可以使用 [ServiceFilter]
屬性,將動作篩選套用至 Controller 或 Action
[ServiceFilter(typeof(ClientIpCheckActionFilter))]
[HttpGet]
public IEnumerable<string> Get()
public class ClientIpCheckPageFilter : IPageFilter
{
private readonly ILogger _logger;
private readonly IPAddress[] _safelist;
public ClientIpCheckPageFilter(
string safelist,
ILogger logger)
{
var ips = safelist.Split(';');
_safelist = new IPAddress[ips.Length];
for (var i = 0; i < ips.Length; i++)
{
_safelist[i] = IPAddress.Parse(ips[i]);
}
_logger = logger;
}
public void OnPageHandlerExecuting(PageHandlerExecutingContext context)
{
var remoteIp = context.HttpContext.Connection.RemoteIpAddress;
if (remoteIp.IsIPv4MappedToIPv6)
{
remoteIp = remoteIp.MapToIPv4();
}
_logger.LogDebug(
"Remote IpAddress: {RemoteIp}", remoteIp);
var badIp = true;
foreach (var testIp in _safelist)
{
if (testIp.Equals(remoteIp))
{
badIp = false;
break;
}
}
if (badIp)
{
_logger.LogWarning(
"Forbidden Request from Remote IP address: {RemoteIp}", remoteIp);
context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
return;
}
}
public void OnPageHandlerExecuted(PageHandlerExecutedContext context)
{
}
public void OnPageHandlerSelected(PageHandlerSelectedContext context)
{
}
}
藉 Razor 由將 Pages 篩選新增至 MVC 篩選集合來啟用 Pages 篩選。
Program.cs
services.AddRazorPages()
.AddMvcOptions(options =>
{
var logger = LoggerFactory.Create(builder => builder.AddConsole())
.CreateLogger<ClientIpCheckPageFilter>();
var filter = new ClientIpCheckPageFilter(
Configuration["AllowList"], logger);
options.Filters.Add(filter);
});
Client IP safelist for ASP.NET Core
Preventing Open Redirection Attacks (C#)