这里是初学者,不要生气。想象一下您正在为某个组织编写一个网站。公共网站将有前端#1,管理面板将有前端#2(他们将通过它更新该网站的内容)。
案例1
在一个解决方案中拥有 2 个独立的后端:
然后,您可以单独部署应用程序,限制仅来自特定网络或静态 IP 的对 AdminApi 的请求。
案例2
只有一个API,只需将[授权]到某些路线即可绕过它。问题是这足够安全吗?因为从理论上讲,您将在全球范围内公开管理面板的路由(仅对其进行一些 jwt 身份验证)。如何使这些端点在一个 API 中全局不可见?更重要的是我应该打扰吗?
你会怎么做?为什么?目标是确保应用程序安全。
附注
我的设置是:.Net 8,Nginx
您能否更具体地介绍一下中间件部分?有没有我可以阅读的来源,或者你能告诉我你的意思是什么,它会是什么样子,你会用它实现什么?
当然,有多种方法可以实现这一点,中间件用于进入此应用程序的所有请求。
示例代码如下:
在appsettings.json中,您可以如下设置AdminSafeList:
{
"AdminSafeList": "127.0.0.1;192.168.1.5;::1",
"Logging": {
然后在中间件里面,可以参考下面的代码:
public class AdminSafeListMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<AdminSafeListMiddleware> _logger;
private readonly byte[][] _safelist;
public AdminSafeListMiddleware(
RequestDelegate next,
ILogger<AdminSafeListMiddleware> 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)
{
// here you could also check the request path by using the reuqest.path
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(
"Forbidden Request from Remote IP address: {RemoteIp}", remoteIp);
context.Response.StatusCode = (int) HttpStatusCode.Forbidden;
return;
}
}
await _next.Invoke(context);
}
}
如果您只想让它适用于特定的 MVC 控制器,您可以使用操作过滤器。
像这样:
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);
}
}
在程序.cs内注册:
services.AddScoped<ClientIpCheckActionFilter>(container =>
{
var loggerFactory = container.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger<ClientIpCheckActionFilter>();
return new ClientIpCheckActionFilter(
Configuration["AdminSafeList"], logger);
});
用途:
[ServiceFilter(typeof(ClientIpCheckActionFilter))]
[HttpGet]
public IEnumerable<string> Get()
更多详情,您可以参考这篇MSFT文章。