【问题标题】:How do you restrict requests so they only work if it is accessed by a specific domain您如何限制请求,使其仅在特定域访问时才有效
【发布时间】:2021-08-22 23:19:12
【问题描述】:

我有这个 ASP.NET Web API,我想限制访问,所以它只在特定主机调用时才有效。就我目前所知,我不能通过令牌来保护它,因为 WEB API url 将是系统的回发 url,系统会在执行特定操作时自动调用它。我已经检查了 CORS,但 CORS 似乎做的是允许特定域访问 API。那么,这是否意味着我的 WEB API 已经被其他域限制了?那为什么我可以通过 Postman 在本地访问它,即使它托管在 Azure 中?

我只希望我的服务只允许来自本地主机和另一个特定域的调用。

我如何做到这一点?

谢谢!

【问题讨论】:

    标签: c# asp.net-web-api asp.net-web-api2


    【解决方案1】:

    一种可能性是使用自定义authorization filter 创建一个带有失败状态代码的 HTTP 响应,例如 400 bad request 或 404 not found 如果请求具有不允许的主机。我们可以定义一个名为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");
            }
        }
    }
    

    如果要全局应用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());
        }
    }
    

    使用此设置,如果我从构造函数中删除“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!");
    }
    

    如果您不想要常量值并且不想全局应用过滤器,那么您可以将IConfiguration 注入过滤器以读取可以访问资源的允许主机。

    【讨论】:

    • 嗨@SamyCode。 RestrictDomain 过滤器正是这样做的。它将限制主机不在AllowedHosts 中的每个请求。所以如果我在RestrictDomain的构造函数中包含“example.com”,那么每个不是来自example.com的请求都会导致HTTP响应失败。
    • stackoverflow.com/a/69945182/331281 怎么样?似乎依赖Host 标头并不安全。
    【解决方案2】:

    CORS 本身只告诉浏览器/客户端应用程序停止发送请求,在许多 ASP.Net Web API 实现中它实际上并没有阻塞请求管道。这就是 Postman 工作的原因,Postman 不会执行相同的 pre-flight OPTIONS 先检查,它只是发送请求。

    您绝对应该考虑向您的 API 添加身份验证,基于 Bearer 令牌的身份验证在 API 之间以及在 API 之间都可以很好地工作。阅读Secure a Web API with Individual Accounts and Local Login in ASP.NET Web API 2.2,但这超出了这个问题的范围。

    在概念层面上,您只需要在 API 中间件之前拦截 OWIN 管道中的传入请求,并在它不符合您的规则时请求该请求。这应该与 CORS 一起使用,以便浏览器以标准方式响应。

    有关背景,请阅读Block or limit unwanted traffic to Asp.Net Web Application。通常我们在托管架构或路由中管理域或 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.
    }
    

    如果您使用 OWIN 托管管道并且您想在全球范围内管理它,那么您可以检查 global.asax.cs 以处理 Application_BeginRequest

       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");
           }
       }
    

    【讨论】:

      猜你喜欢
      • 2021-11-12
      • 2014-08-13
      • 2019-11-23
      • 2015-10-08
      • 1970-01-01
      • 1970-01-01
      • 2023-03-11
      • 2012-12-15
      相关资源
      最近更新 更多