如何保护 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");
此限制适用于来自浏览器的请求。但是,如果请求来自 Postman
、Fiddler
等 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
的请求。部署到服务器时将被删除。
我怀疑这个解决方案也可以通过某种方式绕过。但是,我希望它适用于大多数情况。
我有几个 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");
此限制适用于来自浏览器的请求。但是,如果请求来自 Postman
、Fiddler
等 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
的请求。部署到服务器时将被删除。
我怀疑这个解决方案也可以通过某种方式绕过。但是,我希望它适用于大多数情况。