来自 ASP NET Web API 的 CORS 阻止 Ajax POST 调用 - 对预检请求的响应未通过访问控制检查
Posted
技术标签:
【中文标题】来自 ASP NET Web API 的 CORS 阻止 Ajax POST 调用 - 对预检请求的响应未通过访问控制检查【英文标题】:Ajax POST call blocked by CORS from ASP NET Web API - Response to preflight request doesn't pass access control check 【发布时间】:2020-06-24 10:35:48 【问题描述】:问题总结:
我有两个托管在不同域中的 Web 项目。在对我的 Web API 项目进行 ajax 调用时,我得到以下信息:
CORS 已阻止从源 '' 访问 '' 处的 XMLHttpRequest 策略:对预检请求的响应未通过访问控制 检查:没有“Access-Control-Allow-Origin”标头出现在 请求的资源。
第一个项目 - Web API
我的第一个项目,即 ASP NET Web API (.Net Framework 4.8)
我为所有人全局启用了 CORS,只是为了确保测试正确通过。
在我的WebApiConfig
文件中,我有以下行。
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
上面有using System.Web.Http.Cors;
。
我的方法没有什么特别的属性,因为我们全局启用了 CORS。
[RoutePrefix("api/Test")]
public class TestController : ApiController
[Route("RequestConnection")]
[HttpPost]
public IHttpActionResult RequestConnection(MasterOnRequestInputModel inputModel)
...some code logic here...
第二个项目 - 带有 AJAX 请求的 javascript
我的第二个项目想在 Web API 中调用上述方法。
我的 ajax 调用如下所示:
$.ajax(
type: "POST",
url: myUrl,
contentType: "application/json; charset=utf-8",
dataType: 'json',
data:
'Body': body,
'Head': head,
'Width': width,
'Height': height
,
success: screencastControllerPostSuccess
);
在 Chrome 中,请求如下所示:
我做错了什么?
编辑:
回答
如果你们这样做了,正如上面所写的那样,你应该对 CORS 绝对没有问题。
我的问题是我们公司正在使用的WAF。 WAF 拒绝了我的请求,因为它是潜在的攻击。这是因为我在请求正文中发送 html 元素。我们与我的系统管理员同事一起解决了这个问题。
所以有趣的部分是,在我的请求被 WAF 拒绝后,它返回一个错误,就好像问题出在 CORS 上一样。那是因为请求确实是跨域的,但是拒绝请求后的 WAF 通用响应没有Access-Control-Allow-Origin
标头。
【问题讨论】:
“跨域”服务器是否处理“OPTIONS”请求?这就是飞行前的意义 是的,确实如此。我在想我在 ASP 网络控制器中遗漏了一些东西。或者可能是 ajax 中的一些标题? 很明显,因为 OPTIONS 响应标头缺少所需的访问控制标头In Chrome the request looks as follow:
- response 标头是什么样的 - 请求标头不是问题
它没有。 Failed to load response data
【参考方案1】:
看看www.asp-waf.com 的 WAF,你会发现它很容易处理,也很容易发现类似的问题,因为你只需注册 OnGuardAction 事件,你就可以看到它会被阻止的内容和原因调试它或将其发送到日志。
我们通过像这样使用基类 FireWallBase 来做到这一点
public class MyFireWall : FireWallBase
private readonly ILogger<MyFireWall> _logger;
private bool _agreeWithFirewall = true;
public MyFireWall(
//enable accessing AppConfig
IConfiguration configuration
//allow DI to provide interfaces to base class
, ILoggerFactory? loggerFactory = null, IMemoryCache? memoryCache = null
, IIncidentDatabase? incidentDatabase = null, IWhoisRepository? whoisRepository = null, ISubscriptionsRepository? subscriptions = null
, IEmailReportDesination? emailReportDesination = null, IDatabaseReportDestination? databaseReportDestination = null
, ILoggerReportDesination? loggerReportDestination = null, IFireWallDiskLoggerDestination? diskLoggerDestination = null
, IEventLogReporting? eventLogReporting = null, IGeoFactory? geoFactory = null, ILatLongRepository? latLongRepository = null
, IResetRepository? resetRepository = null)
: base(loggerFactory, memoryCache, incidentDatabase, whoisRepository, subscriptions, emailReportDesination, databaseReportDestination
, loggerReportDestination, diskLoggerDestination, eventLogReporting, geoFactory, latLongRepository, resetRepository)
var section = configuration.GetSection("FireWall");
if (section.Exists())
_isReccommendOnly = section.GetValue<bool>("AgreeWithFirewall");
base.Trigger_OnFireWallCreated(this);
OnIncident += MyFireWall_OnIncident;
OnGuardAction += MyFireWall_OnGuardAction;
OnUserTypeChange += MyFireWall_OnUserTypeChange;
_logger = loggerFactory.CreateLogger<MyFireWall>();
private void MyFireWall_OnUserTypeChange(object? sender, Walter.Web.FireWall.EventArguments.UserTypeChangedEventArgs e)
_logger?.LogCritical("oldType : newType\n route\n Rules:\n data"
, e.OriginalType
, e.NewType
, e.Rout
, string.Join("\n ", e.Rules)
);
//allow the change
e.Allow = true;
if (e.OriginalType.HasFlag(UserTypes.IsSearchEngine) && e.NewType.HasFlag(UserTypes.IsMalicious))
//remove the malicious flag from search engines to not prevent search engines from
//indexing the site
e.NewType &= ~UserTypes.IsMalicious;
private void MyFireWall_OnGuardAction(object? sender, Walter.Web.FireWall.EventArguments.GuardActionEventArgs e)
_logger?.LogCritical("Method page : route\n action:RuleNr\n Reasons:Reason\n data"
, e.Page.Method
, e.Page.OriginalUrl.AbsolutePath
, e.Page.FireWallRoute
, e.Action
, string.Join("\n ", e.Page.PageViolationStack.Select(s => s.ToString()))
);
//allow the firewall to block requests
e.Allow = _agreeWithFirewall;
private void MyFireWall_OnIncident(object? sender, Walter.Web.FireWall.EventArguments.FireWallIncidentEventArgs e)
_logger?.LogCritical("Method page : route\n rule:RuleNr\n Reasons:Reason\n data"
, e.Page.Method
, e.Page.OriginalUrl.AbsolutePath
, e.Page.FireWallRoute
, e.StackEntry.Rule
, e.StackEntry.RuleNr
, e.StackEntry.Reason
, string.Join("\n ", e.Data.Select(s => $"s.Key:s.Value"))
);
//allow the firewall to raise incidents
e.Allow = _agreeWithFirewall;
我们通过依赖注入启用防火墙,就像 .net Web 应用程序中的其他所有功能一样。我可以像这样使用它来启用我自己的防火墙类:
services.AddFireWall<MyFireWall>("Token", "Key", new Uri(Configuration["domainUri"], UriKind.Absolute), options =>
//add your options here
);
在选项中,您可以在 options.Rules.Headers 下配置 CORS,但您可以做的远不止这些。
防火墙在我的 NuGet 包中 Walter.Web.FireWall.* 有很多附加组件,例如地理以及使用时间跨度定时向 SMTP 报告,您可以每天收到电子邮件,而不会在用户被阻止时被邮件淹没.
【讨论】:
看看asp-waf.com/download/ASP-WAF-FireWall-Getting-Started.pdf以上是关于来自 ASP NET Web API 的 CORS 阻止 Ajax POST 调用 - 对预检请求的响应未通过访问控制检查的主要内容,如果未能解决你的问题,请参考以下文章
通过微软的cors类库,让ASP.NET Web API 支持 CORS
我正在将我的 asp.net web api 迁移到 asp.net core。 Cors 迁移