Sam*_*ode 5 c# asp.net-web-api asp.net-web-api2
我有这个 ASP.NET Web API,我想限制访问,所以它只在被特定主机调用时才有效。就我目前所知,我无法通过令牌保护它,因为 WEB API url 将是系统的回发 url,该系统将在执行特定操作时自动调用它。我已经检查了 CORS,但 CORS 似乎是允许特定域访问 API。那么,这是否意味着我的 WEB API 已经被其他域限制了?那为什么我可以通过Postman本地访问它,即使它托管在Azure中?
我只希望我的服务只允许来自本地主机和另一个特定域的调用。
我如何实现这一目标?
谢谢!
Jos*_*mil 15
一种可能性是使用自定义授权过滤器,该过滤器创建一个带有失败状态代码的 HTTP 响应,例如 400 错误请求或 404 未找到(如果请求具有不允许的主机)。我们可以定义一个授权过滤器,名称RestrictDomain如下:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
public class RestrictDomainAttribute : Attribute, IAuthorizationFilter
{
public IEnumerable<string> AllowedHosts { get; }
public RestrictDomainAttribute(params string[] allowedHosts) => AllowedHosts = allowedHosts;
public void OnAuthorization(AuthorizationFilterContext context)
{
// Get host from the request and check if it's in the enumeration of allowed hosts
string host = context.HttpContext.Request.Host.Host;
if (!AllowedHosts.Contains(host, StringComparer.OrdinalIgnoreCase))
{
// Request came from an authorized host, return bad request
context.Result = new BadRequestObjectResult("Host is not allowed");
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果您想全局应用RestrictDomain过滤器,则可以在Startup.cs文件中添加过滤器,如下所示:
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
{
// Add the restrict domain filter globally
// You could read the allowed hosts from a config file, here we hard code them
options.Filters.Add(new RestrictDomainAttribute("localhost", "example.com"));
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints => endpoints.MapControllers());
}
}
Run Code Online (Sandbox Code Playgroud)
通过此设置,如果我从构造函数中删除“localhost”并仅允许“example.com”,则当我使用 Postman 时,我会收到 400 请求,因为主机将是 localhost。
另一种选择是直接在控制器或控制器操作中使用过滤器,因为我们将其配置为作为属性工作。但是,允许的主机必须是常量值,而不是可以在运行时计算的值。这是一个例子:
using Microsoft.AspNetCore.Mvc;
[Route("")]
[ApiController]
public class HomeController : ControllerBase
{
[HttpGet]
public ContentResult Index() => Content("Home");
[HttpGet("greeting")]
[RestrictDomain("localhost", "example.com")] // values must be constants
public ContentResult Greeting() => Content("Hello, World!");
}
Run Code Online (Sandbox Code Playgroud)
如果您不需要常量值并且不想全局应用过滤器,那么您可以将 注入IConfiguration过滤器以读取可以访问资源的允许主机。
CORS本身仅告诉浏览器/客户端应用程序停止发送请求,在许多 ASP.Net Web API 实现中,它实际上并不阻止请求管道。这就是 Postman 工作的原因,Postman 不会首先执行相同的飞行前 OPTIONS检查,它只是发送请求。
您绝对应该考虑向您的 API 添加身份验证,基于不记名令牌的身份验证在 API 中以及 API 之间都能很好地工作。请阅读ASP.NET Web API 2.2 中使用个人帐户和本地登录保护 Web API 的安全,但这超出了此问题的范围。
在概念层面上,您只需在 API 中间件之前拦截 OWIN 管道中的传入请求,并在不符合您的规则时发出请求。这应该与CORS结合使用,以便浏览器以标准方式响应。
有关背景知识,请阅读“阻止或限制 Asp.Net Web 应用程序的不需要的流量”。通常我们在托管架构或路由中管理域或 IP 级别的安全过滤。IIS 或 Azure 主机有许多内置策略来帮助管理此问题。
您可以通过添加以下 OWIN 请求处理器在全局级别实现此目的:
public void ConfigureOAuth(IAppBuilder app)
{
app.Use((context, next) =>
{
string[] AllowedDomains = new string[] { "::1", "localhost", "mybusinessdomain.com" };
if (!AllowedDomains.Contains(context.Request.Host.Value.ToLower()))
{
context.Response.StatusCode = (int)System.Net.HttpStatusCode.Forbidden;
return System.Threading.Tasks.Task.FromResult<object>(null);
}
return next();
});
// TODO: add in your other OWIN configuration AFTER the request filter.
}
Run Code Online (Sandbox Code Playgroud)
如果您不使用 OWIN 托管管道并且想要全局管理它,那么您可以检查 global.asax.cs 来处理
Application_BeginRequest:Run Code Online (Sandbox Code Playgroud)private static readonly string[] AllowedDomains = new string[] { "::1", "localhost", "mybusinessdomain.com" }; protected void Application_BeginRequest(Object sender, EventArgs e) { if >(!AllowedDomains.Contains(HttpContext.Current.Request.UserHostName.ToLower())) { HttpContext.Current.Response.StatusCode = (int)System.Net.HttpStatusCode.Forbidden; HttpContext.Current.Response.End(); // or transfer to a specific page // Server.Transfer("~/banned.aspx"); } }
| 归档时间: |
|
| 查看次数: |
387 次 |
| 最近记录: |