ASP.NET Core 的客户端 IP 安全安全Client IP safelist for ASP.NET Core

本文内容

作者: Damien BowdenTom Dykstra

本文介绍三种在 ASP.NET Core 应用程序中实现 IP 安全列表(也称为白名单)的方法。可用工具如下:

  • 用于检查每个请求的远程 IP 地址的中间件。
  • 操作筛选器来检查针对特定控制器或操作方法的请求的远程 IP 地址。
  • Razor Pages 筛选器来检查 Razor 页面的请求的远程 IP 地址。

在每种情况下,包含批准的客户端 IP 地址的字符串存储在应用设置中。中间件或筛选器会将字符串分析为一个列表,并检查远程 IP 是否在列表中。如果不是,则返回 HTTP 403 禁止的状态代码。

查看或下载示例代码如何下载

安全安全The safelist

appsettings文件中配置该列表。它是以分号分隔的列表,并且可以包含 IPv4 和 IPv6 地址。

  1. {
  2. "AdminSafeList": "127.0.0.1;192.168.1.5;::1",
  3. "Logging": {
  4. "IncludeScopes": false,
  5. "LogLevel": {
  6. "Default": "Debug",
  7. "System": "Information",
  8. "Microsoft": "Information"
  9. }
  10. }
  11. }

中间件Middleware

Configure 方法将添加中间件,并在构造函数参数中将安全项的字符串传递给它。

  1. public void Configure(
  2. IApplicationBuilder app,
  3. IHostingEnvironment env,
  4. ILoggerFactory loggerFactory)
  5. {
  6. loggerFactory.AddNLog();
  7. app.UseStaticFiles();
  8. app.UseMiddleware<AdminSafeListMiddleware>(Configuration["AdminSafeList"]);
  9. app.UseMvc();
  10. }

中间件将字符串分析为数组,并在数组中查找远程 IP 地址。如果找不到远程 IP 地址,中间件将返回 HTTP 401 禁止访问。对于 HTTP Get 请求,将跳过此验证过程。

  1. public class AdminSafeListMiddleware
  2. {
  3. private readonly RequestDelegate _next;
  4. private readonly ILogger<AdminSafeListMiddleware> _logger;
  5. private readonly string _adminSafeList;
  6. public AdminSafeListMiddleware(
  7. RequestDelegate next,
  8. ILogger<AdminSafeListMiddleware> logger,
  9. string adminSafeList)
  10. {
  11. _adminSafeList = adminSafeList;
  12. _next = next;
  13. _logger = logger;
  14. }
  15. public async Task Invoke(HttpContext context)
  16. {
  17. if (context.Request.Method != "GET")
  18. {
  19. var remoteIp = context.Connection.RemoteIpAddress;
  20. _logger.LogDebug("Request from Remote IP address: {RemoteIp}", remoteIp);
  21. string[] ip = _adminSafeList.Split(';');
  22. var bytes = remoteIp.GetAddressBytes();
  23. var badIp = true;
  24. foreach (var address in ip)
  25. {
  26. var testIp = IPAddress.Parse(address);
  27. if(testIp.GetAddressBytes().SequenceEqual(bytes))
  28. {
  29. badIp = false;
  30. break;
  31. }
  32. }
  33. if(badIp)
  34. {
  35. _logger.LogInformation(
  36. "Forbidden Request from Remote IP address: {RemoteIp}", remoteIp);
  37. context.Response.StatusCode = 401;
  38. return;
  39. }
  40. }
  41. await _next.Invoke(context);
  42. }
  43. }

操作筛选器Action filter

如果只希望特定控制器或操作方法使用 "安全",请使用操作筛选器。下面是一个示例:

  1. using System.Linq;
  2. using System.Net;
  3. using System.Threading.Tasks;
  4. using Microsoft.AspNetCore.Authorization;
  5. using Microsoft.AspNetCore.Mvc;
  6. using Microsoft.AspNetCore.Mvc.Authorization;
  7. using Microsoft.AspNetCore.Mvc.Filters;
  8. using Microsoft.Extensions.Configuration;
  9. using Microsoft.Extensions.Logging;
  10. namespace ClientIpAspNetCore.Filters
  11. {
  12. public class ClientIpCheckFilter : ActionFilterAttribute
  13. {
  14. private readonly ILogger _logger;
  15. private readonly string _safelist;
  16. public ClientIpCheckFilter
  17. (ILoggerFactory loggerFactory, IConfiguration configuration)
  18. {
  19. _logger = loggerFactory.CreateLogger("ClientIdCheckFilter");
  20. _safelist = configuration["AdminSafeList"];
  21. }
  22. public override void OnActionExecuting(ActionExecutingContext context)
  23. {
  24. var remoteIp = context.HttpContext.Connection.RemoteIpAddress;
  25. _logger.LogInformation(
  26. "Remote IpAddress: {RemoteIp}", remoteIp);
  27. string[] ip = _safelist.Split(';');
  28. var badIp = true;
  29. foreach (var address in ip)
  30. {
  31. if (remoteIp.IsIPv4MappedToIPv6)
  32. {
  33. remoteIp = remoteIp.MapToIPv4();
  34. }
  35. var testIp = IPAddress.Parse(address);
  36. if (testIp.Equals(remoteIp))
  37. {
  38. badIp = false;
  39. break;
  40. }
  41. }
  42. if (badIp)
  43. {
  44. _logger.LogInformation(
  45. "Forbidden Request from Remote IP address: {RemoteIp}", remoteIp);
  46. context.Result = new StatusCodeResult(401);
  47. return;
  48. }
  49. base.OnActionExecuting(context);
  50. }
  51. }
  52. }

操作筛选器将添加到服务容器中。

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddScoped<ClientIpCheckFilter>();
  4. services.AddMvc(options =>
  5. {
  6. options.Filters.Add
  7. (new ClientIpCheckPageFilter
  8. (_loggerFactory, Configuration));
  9. }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
  10. }

然后,可以在控制器或操作方法上使用该筛选器。

  1. [ServiceFilter(typeof(ClientIpCheckFilter))]
  2. [HttpGet]
  3. public IEnumerable<string> Get()

在示例应用中,筛选器将应用于 Get 方法。因此,当你通过发送 Get API 请求来测试应用时,属性将验证客户端 IP 地址。当你通过使用任何其他 HTTP 方法调用 API 进行测试时,中间件将验证客户端 IP。

Razor Pages 筛选器Razor Pages filter

如果需要 Razor Pages 应用的安全安全,请使用 Razor Pages 筛选器。下面是一个示例:

  1. using Microsoft.AspNetCore.Mvc;
  2. using Microsoft.AspNetCore.Mvc.Filters;
  3. using Microsoft.Extensions.Configuration;
  4. using Microsoft.Extensions.Logging;
  5. using System;
  6. using System.Linq;
  7. using System.Net;
  8. namespace ClientIpAspNetCore
  9. {
  10. public class ClientIpCheckPageFilter : IPageFilter
  11. {
  12. private readonly ILogger _logger;
  13. private readonly string _safelist;
  14. public ClientIpCheckPageFilter
  15. (ILoggerFactory loggerFactory, IConfiguration configuration)
  16. {
  17. _logger = loggerFactory.CreateLogger("ClientIdCheckPageFilter");
  18. _safelist = configuration["AdminSafeList"];
  19. }
  20. public void OnPageHandlerExecuting(PageHandlerExecutingContext context)
  21. {
  22. var remoteIp = context.HttpContext.Connection.RemoteIpAddress;
  23. _logger.LogInformation(
  24. "Remote IpAddress: {RemoteIp}", remoteIp);
  25. string[] ip = _safelist.Split(';');
  26. var badIp = true;
  27. foreach (var address in ip)
  28. {
  29. if (remoteIp.IsIPv4MappedToIPv6)
  30. {
  31. remoteIp = remoteIp.MapToIPv4();
  32. }
  33. var testIp = IPAddress.Parse(address);
  34. if (testIp.Equals(remoteIp))
  35. {
  36. badIp = false;
  37. break;
  38. }
  39. }
  40. if (badIp)
  41. {
  42. _logger.LogInformation(
  43. "Forbidden Request from Remote IP address: {RemoteIp}", remoteIp);
  44. context.Result = new StatusCodeResult(401);
  45. return;
  46. }
  47. }
  48. public void OnPageHandlerExecuted(PageHandlerExecutedContext context)
  49. {
  50. }
  51. public void OnPageHandlerSelected(PageHandlerSelectedContext context)
  52. {
  53. }
  54. }
  55. }

此筛选器通过将其添加到 MVC 筛选器集合来启用。

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddScoped<ClientIpCheckFilter>();
  4. services.AddMvc(options =>
  5. {
  6. options.Filters.Add
  7. (new ClientIpCheckPageFilter
  8. (_loggerFactory, Configuration));
  9. }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
  10. }

当你运行应用并请求 Razor 页面时,Razor Pages 筛选器将验证客户端 IP。

后续步骤Next steps

了解有关 ASP.NET Core 中间件的详细信息