如何保护 open/public Web API 端点

How to protect open/public Web API endpoints

我有几个 Web API 没有 authentication/authorization 的端点,因为它也可以用于来宾用户。这些端点将通过 XHR/Ajax/JS 直接使用。但是,我只想允许来自几个来源的请求。为此,我使用了如下所示的 Cors 中间件:

配置服务方法

services.AddCors(options =>
{
    options.AddPolicy("AllowSpecific", builder => 
        builder.WithOrigins("http://localhost:55476")
            .AllowAnyHeader()
            .AllowAnyMethod());
});

配置方法

app.UseCors("AllowSpecific");

此限制适用于来自浏览器的请求。但是,如果请求来自 PostmanFiddler 等 Http 客户端,则请求会通过。

有什么办法可以解决这种情况吗?

由于目前没有更好的选择,我用自定义中间件替换了 CORS 中间件,它将检查每个请求的 header Origin 和 allow/restrict 基于配置上。这适用于 cross-browser 请求和 HTTP 客户端请求。

中间件

public class OriginRestrictionMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IConfiguration _configuration;
    private readonly ILogger _logger;

    public OriginRestrictionMiddleware(RequestDelegate next, IConfiguration configuration, ILoggerFactory loggerFactory)
    {
        _next = next;
        _configuration = configuration;
        _logger = loggerFactory.CreateLogger<OriginRestrictionMiddleware>();
    }

    public Task Invoke(HttpContext context)
    {
        try
        {
            var allowedOriginsConfig = _configuration.GetSection("AllowedOrigins").Value;

            var allowedOrigins = allowedOriginsConfig.Split(',');

            _logger.LogInformation("Allowed Origins: " + allowedOriginsConfig);

            var originHeader = context.Request.Headers.Where(h => h.Key == "Origin");
            if (originHeader.Any())
            {
                var requestOrigin = originHeader.First().Value.ToString();

                _logger.LogInformation("Request Origin: " + requestOrigin);

                foreach (var origin in allowedOrigins)
                {
                    //if(origin.StartsWith(requestOrigin))
                    if (requestOrigin.Contains(origin))
                    {
                        return _next(context);
                    }
                }
            }

            context.Response.StatusCode = 401;
            return context.Response.WriteAsync("Not Authorized");
        }
        catch(Exception ex)
        {
            _logger.LogInformation(ex.ToString());
            throw;
        }
    }
}

public static class OriginRestrictionMiddlewareExtension
{
    public static IApplicationBuilder UseOriginRestriction(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<OriginRestrictionMiddleware>();
    }
}

启动配置

app.UseOriginRestriction();

AppSettings.json

"AllowedOrigins": "http://localhost:55476,http://localhost:55477,chrome-extension"

chrome-extension 入口允许在开发期间来自 Postman 的请求。部署到服务器时将被删除。

我怀疑这个解决方案也可以通过某种方式绕过。但是,我希望它适用于大多数情况。