原文链接:Client IP safelist for ASP.NET Core
<https://docs.microsoft.com/en-us/aspnet/core/security/ip-safelist?view=aspnetcore-2.2>
作者:Damien Bowden <https://twitter.com/damien_bod> and Tom Dykstra
<https://github.com/tdykstra>
译者:Lamond Lu



本篇博文中展示了如何在ASP.NET Core应用程序中设置IP白名单验证的3种方式。

你可以使用一下3种方式:

* 使用中间件检查每个请求的远程IP地址
* 使用Action过滤器为指定的Controller或action方法添加针对远程IP地址的检查
* 使用IPageFilter为Razor Pages应用添加针对远程IP地址的检查
查看项目源代码
<https://github.com/aspnet/Docs/tree/master/aspnetcore/security/ip-safelist/samples/2.x/ClientIpAspNetCore>

白名单

这里为了简化代码,我们将IP白名单列表放置在配置文件appSettings.json中,每个IP之间使用分号分隔。

正式项目中,可以将这个列表保存在数据库中,便于管理
{ "AdminSafeList": "127.0.0.1;192.168.1.5;::1", "Logging": { "IncludeScopes":
false, "LogLevel": { "Default": "Debug", "System": "Information", "Microsoft":
"Information" } } }
使用中间件检查每个请求的远程IP地址

这里我们首先添加一个中间件AdminSafeListMiddleware。
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}"); 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}"); context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
return; } } await _next.Invoke(context); } }
代码解释:

* 这里在AdminSafeListMiddleware的构造函数中,我们传入了从配置文件中读取的IP白名单列表
* 当请求进入当前中间件时,我们使用当前请求上下文的context.Connection.RemoteIpAddress获取到了客户端的IP
* 如果客户端IP存在于IP白名单列表中,就运行下一个中间件,否则就直接返回401状态码。
* 这里源代码中,只过滤了非GET请求,如果针对GET请求也需要启动IP白名单,可以去掉这个判断。
然后我们需要在Startup.cs文件的Configure方法中将中间件添加到ASP.NET Core的中间件管道中。
public void Configure( IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory) { loggerFactory.AddNLog(); app.UseStaticFiles();
app.UseMiddleware<AdminSafeListMiddleware>( Configuration["AdminSafeList"]);
app.UseMvc(); }
注意: 这里我们在注册中间件的时候,传入了从配置文件中读取的IP白名单。

使用Action过滤器

如果你只是希望为某些特性的Controller或Action方法添加IP白名单,你可以使用Action过滤器。

这里我们首先添加一个新类ClientIdCheckFilter, 它继承自ActionFilterAttribute
public class ClientIdCheckFilter : ActionFilterAttribute { private readonly
ILogger _logger; private readonly string _safelist; public ClientIdCheckFilter
(ILoggerFactory loggerFactory, IConfiguration configuration) { _logger =
loggerFactory.CreateLogger("ClientIdCheckFilter"); _safelist =
configuration["AdminSafeList"]; } public override void
OnActionExecuting(ActionExecutingContext context) { _logger.LogInformation(
$"Remote IpAddress: {context.HttpContext.Connection.RemoteIpAddress}"); var
remoteIp = context.HttpContext.Connection.RemoteIpAddress;
_logger.LogDebug($"Request from Remote IP address: {remoteIp}"); string[] ip =
_safelist.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}"); context.Result = new StatusCodeResult(401); return; }
base.OnActionExecuting(context); } }
这里代码逻辑和前面中间的基本一样,主要的区别是

* 这里我们是从IP白名单,我们是从IConfiguration对象中手动获取的
* 这里我们复写了OnActionExecuting方法,如果当前客户端 IP存在于白名单中,我们就调用基类OnActionExecuting
方法,执行当前Action请求,否则就返回一个401状态码
* 这里没有针对请求类型的判断,所以指定当前过滤器的Action,GET请求也会受到白名单的限制
第二步,我们需要将这action过滤器添加到服务容器中。
public void ConfigureServices(IServiceCollection services) {
services.AddScoped<ClientIdCheckFilter>(); services.AddMvc(options => {
options.Filters.Add (new ClientIdCheckPageFilter (_loggerFactory,
Configuration)); }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1); }
第三步,我们可以在Action方法声明处添加ServiceFilter特性,传入的参数是我们之前定义好的ClientIdCheckFilter。

例:
[ServiceFilter(typeof(ClientIdCheckFilter))] [HttpGet] public
IEnumerable<string> Get()
使用IPageFilter

Razor Pages应用是ASP.NET Core 2.0中新引入的功能,它是ASP.NET Core Mvc的一个子集。

如果希望Razor Pages应用支持IP白名单,我们需要创建一个新类ClientIdCheckPageFilter, 它实现了IPageFilter接口.
public class ClientIdCheckPageFilter : IPageFilter { private readonly ILogger
_logger; private readonly string _safelist; public ClientIdCheckPageFilter
(ILoggerFactory loggerFactory, IConfiguration configuration) { _logger =
loggerFactory.CreateLogger("ClientIdCheckPageFilter"); _safelist =
configuration["AdminSafeList"]; } public void
OnPageHandlerExecuting(PageHandlerExecutingContext context) {
_logger.LogInformation( $"Remote IpAddress:
{context.HttpContext.Connection.RemoteIpAddress}"); var remoteIp =
context.HttpContext.Connection.RemoteIpAddress; _logger.LogDebug($"Request from
Remote IP address: {remoteIp}"); string[] ip = _safelist.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}"); context.Result = new StatusCodeResult(401); return; } } public
void OnPageHandlerExecuted(PageHandlerExecutedContext context) { } public void
OnPageHandlerSelected(PageHandlerSelectedContext context) { } }
这里的代码实现和IActionFilter的实现基本一样,唯一的区别是代码放在了OnPageHandlerExecuting的实现中。

第二步,我们还是需要将ClientIdCheckPageFilter添加到MVC的过滤器集合中。
public void ConfigureServices(IServiceCollection services) {
services.AddScoped<ClientIdCheckFilter>(); services.AddMvc(options => {
options.Filters.Add (new ClientIdCheckPageFilter (_loggerFactory,
Configuration)); }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1); }
总结

本篇我们讲解了在ASP.NET Core中启用IP白名单验证的3种方式

* 使用中间件检查每个请求的远程IP地址
* 使用Action过滤器为指定的Controller或action方法添加针对远程IP地址的检查
* 使用IPageFilter为Razor Pages应用添加针对远程IP地址的检查

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信