ASP.NET Core 的客户端 IP 安全安全Client IP safelist for ASP.NET Core
本文内容
本文介绍三种在 ASP.NET Core 应用程序中实现 IP 安全列表(也称为白名单)的方法。可用工具如下:
- 用于检查每个请求的远程 IP 地址的中间件。
- 操作筛选器来检查针对特定控制器或操作方法的请求的远程 IP 地址。
- Razor Pages 筛选器来检查 Razor 页面的请求的远程 IP 地址。
在每种情况下,包含批准的客户端 IP 地址的字符串存储在应用设置中。中间件或筛选器会将字符串分析为一个列表,并检查远程 IP 是否在列表中。如果不是,则返回 HTTP 403 禁止的状态代码。
安全安全The safelist
在appsettings文件中配置该列表。它是以分号分隔的列表,并且可以包含 IPv4 和 IPv6 地址。
{
"AdminSafeList": "127.0.0.1;192.168.1.5;::1",
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
中间件Middleware
Configure
方法将添加中间件,并在构造函数参数中将安全项的字符串传递给它。
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
loggerFactory.AddNLog();
app.UseStaticFiles();
app.UseMiddleware<AdminSafeListMiddleware>(Configuration["AdminSafeList"]);
app.UseMvc();
}
中间件将字符串分析为数组,并在数组中查找远程 IP 地址。如果找不到远程 IP 地址,中间件将返回 HTTP 401 禁止访问。对于 HTTP Get 请求,将跳过此验证过程。
public class AdminSafeListMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<AdminSafeListMiddleware> _logger;
private readonly string _adminSafeList;
public AdminSafeListMiddleware(
RequestDelegate next,
ILogger<AdminSafeListMiddleware> logger,
string adminSafeList)
{
_adminSafeList = adminSafeList;
_next = next;
_logger = logger;
}
public async Task Invoke(HttpContext context)
{
if (context.Request.Method != "GET")
{
var remoteIp = context.Connection.RemoteIpAddress;
_logger.LogDebug("Request from Remote IP address: {RemoteIp}", remoteIp);
string[] ip = _adminSafeList.Split(';');
var bytes = remoteIp.GetAddressBytes();
var badIp = true;
foreach (var address in ip)
{
var testIp = IPAddress.Parse(address);
if(testIp.GetAddressBytes().SequenceEqual(bytes))
{
badIp = false;
break;
}
}
if(badIp)
{
_logger.LogInformation(
"Forbidden Request from Remote IP address: {RemoteIp}", remoteIp);
context.Response.StatusCode = 401;
return;
}
}
await _next.Invoke(context);
}
}
操作筛选器Action filter
如果只希望特定控制器或操作方法使用 "安全",请使用操作筛选器。下面是一个示例:
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace ClientIpAspNetCore.Filters
{
public class ClientIpCheckFilter : ActionFilterAttribute
{
private readonly ILogger _logger;
private readonly string _safelist;
public ClientIpCheckFilter
(ILoggerFactory loggerFactory, IConfiguration configuration)
{
_logger = loggerFactory.CreateLogger("ClientIdCheckFilter");
_safelist = configuration["AdminSafeList"];
}
public override void OnActionExecuting(ActionExecutingContext context)
{
var remoteIp = context.HttpContext.Connection.RemoteIpAddress;
_logger.LogInformation(
"Remote IpAddress: {RemoteIp}", remoteIp);
string[] ip = _safelist.Split(';');
var badIp = true;
foreach (var address in ip)
{
if (remoteIp.IsIPv4MappedToIPv6)
{
remoteIp = remoteIp.MapToIPv4();
}
var testIp = IPAddress.Parse(address);
if (testIp.Equals(remoteIp))
{
badIp = false;
break;
}
}
if (badIp)
{
_logger.LogInformation(
"Forbidden Request from Remote IP address: {RemoteIp}", remoteIp);
context.Result = new StatusCodeResult(401);
return;
}
base.OnActionExecuting(context);
}
}
}
操作筛选器将添加到服务容器中。
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<ClientIpCheckFilter>();
services.AddMvc(options =>
{
options.Filters.Add
(new ClientIpCheckPageFilter
(_loggerFactory, Configuration));
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
然后,可以在控制器或操作方法上使用该筛选器。
[ServiceFilter(typeof(ClientIpCheckFilter))]
[HttpGet]
public IEnumerable<string> Get()
在示例应用中,筛选器将应用于 Get
方法。因此,当你通过发送 Get
API 请求来测试应用时,属性将验证客户端 IP 地址。当你通过使用任何其他 HTTP 方法调用 API 进行测试时,中间件将验证客户端 IP。
Razor Pages 筛选器Razor Pages filter
如果需要 Razor Pages 应用的安全安全,请使用 Razor Pages 筛选器。下面是一个示例:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System;
using System.Linq;
using System.Net;
namespace ClientIpAspNetCore
{
public class ClientIpCheckPageFilter : IPageFilter
{
private readonly ILogger _logger;
private readonly string _safelist;
public ClientIpCheckPageFilter
(ILoggerFactory loggerFactory, IConfiguration configuration)
{
_logger = loggerFactory.CreateLogger("ClientIdCheckPageFilter");
_safelist = configuration["AdminSafeList"];
}
public void OnPageHandlerExecuting(PageHandlerExecutingContext context)
{
var remoteIp = context.HttpContext.Connection.RemoteIpAddress;
_logger.LogInformation(
"Remote IpAddress: {RemoteIp}", remoteIp);
string[] ip = _safelist.Split(';');
var badIp = true;
foreach (var address in ip)
{
if (remoteIp.IsIPv4MappedToIPv6)
{
remoteIp = remoteIp.MapToIPv4();
}
var testIp = IPAddress.Parse(address);
if (testIp.Equals(remoteIp))
{
badIp = false;
break;
}
}
if (badIp)
{
_logger.LogInformation(
"Forbidden Request from Remote IP address: {RemoteIp}", remoteIp);
context.Result = new StatusCodeResult(401);
return;
}
}
public void OnPageHandlerExecuted(PageHandlerExecutedContext context)
{
}
public void OnPageHandlerSelected(PageHandlerSelectedContext context)
{
}
}
}
此筛选器通过将其添加到 MVC 筛选器集合来启用。
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<ClientIpCheckFilter>();
services.AddMvc(options =>
{
options.Filters.Add
(new ClientIpCheckPageFilter
(_loggerFactory, Configuration));
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
当你运行应用并请求 Razor 页面时,Razor Pages 筛选器将验证客户端 IP。