【问题标题】:Web API 2 CORS only stop OPTION, not POSTWeb API 2 CORS 仅停止 OPTION,而不是 POST
【发布时间】:2013-12-05 02:31:55
【问题描述】:

我有一个来自 VS 2013 的 Web API 2 项目,使用来自 Nuget 的 5.0.0.0 DLL(最近加载)。

我还创建了一个限制来源的自定义 CorsPolicy。这似乎工作正常,我按照这里的说明进行操作:http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api

我在 Fiddler 中注意到的是,虽然 OPTIONS 动词被 400 Bad Request 正确阻止,但 POST 动词直接传递给控制器​​,然后调用 CorsPolicy ,但此时 Post 动作已经成功,客户端得到 200 OK 返回。

我希望 POST 被 400 Bad Request 和 OPTION 动词阻塞。如果我正确理解 CORS TR,它应该被阻止。

这是来自单个 POST 的 Web API 的诊断跟踪,我使用 Fiddler 将 Origin 标头设置为 http://localhose。请记住——完全相同的场景会被 OPTION 动词正确地阻止。

w3wp.exe Information: 0 : Request, Method=POST, Url=http://myhost/myvdir/api/v1/MyCntrllr/MyAction, Message='http://myhost/myvdir/api/v1/MyCntrllr/MyAction'
w3wp.exe Information: 0 : Message='MyCntrllr', Operation=DefaultHttpControllerSelector.SelectController
w3wp.exe Information: 0 : Message='MyNamespace.Controllers.MyCntrllrController', Operation=DefaultHttpControllerActivator.Create
w3wp.exe Information: 0 : Message='MyNamespace.Controllers.MyCntrllrController', Operation=HttpControllerDescriptor.CreateController
w3wp.exe Information: 0 : Message='Selected action 'MyAction(Submission submission)'', Operation=ApiControllerActionSelector.SelectAction
w3wp.exe Information: 0 : Message='Value read='{ MyValue1: 24000, MyValue2: 2, MyValues3: 24,34, MyValue4: 0, MyValue5: 90001, MyValue6: c0, MyValue7: 16 }'', Operation=JsonMediaTypeFormatter.ReadFromStreamAsync
w3wp.exe Information: 0 : Message='Parameter 'submission' bound to the value '{ MyValue1: 24000, MyValue2: 2, MyValues3: 24,34, MyValue4: 0, MyValue5: 90001, MyValue6: c0, MyValue7: 16 }'', Operation=FormatterParameterBinding.ExecuteBindingAsync
w3wp.exe Information: 0 : Message='Model state is valid. Values: submission={ MyValue1: 24000, MyValue2: 2, MyValues3: 24,34, MyValue4: 0, MyValue5: 90001, MyValue6: c0, MyValue7: 16 }', Operation=HttpActionBinding.ExecuteBindingAsync
w3wp.exe Information: 0 : Message='Action returned 'MyNamespace.MyConclusion'', Operation=ReflectedHttpActionDescriptor.ExecuteAsync
w3wp.exe Information: 0 : Message='Will use same 'JsonMediaTypeFormatter' formatter', Operation=JsonMediaTypeFormatter.GetPerRequestFormatterInstance
w3wp.exe Information: 0 : Message='Selected formatter='JsonMediaTypeFormatter', content-type='application/json; charset=utf-8'', Operation=DefaultContentNegotiator.Negotiate
w3wp.exe Information: 0 : Operation=ApiControllerActionInvoker.InvokeActionAsync, Status=200 (OK)
w3wp.exe Information: 0 : Operation=MyCntrllrController.ExecuteAsync, Status=200 (OK)
w3wp.exe Information: 0 : Message='CorsPolicyProvider selected: 'MyNamespace.WhiteListOriginPolicyProvider'', Operation=CorsPolicyProviderFactory.GetCorsPolicyProvider
w3wp.exe Information: 0 : Message='CorsPolicy selected: 'AllowAnyHeader: True, AllowAnyMethod: False, AllowAnyOrigin: False, PreflightMaxAge: null, SupportsCredentials: False, Origins: {https://www.example.com,http://localhost:22221}, Methods: {POST,OPTIONS}, Headers: {}, ExposedHeaders: {}'', Operation=WhiteListOriginPolicyProvider.GetCorsPolicyAsync
w3wp.exe Information: 0 : Message='CorsResult returned: 'IsValid: False, AllowCredentials: False, PreflightMaxAge: null, AllowOrigin: , AllowExposedHeaders: {}, AllowHeaders: {}, AllowMethods: {}, ErrorMessages: {The origin 'http://localhose' is not allowed.}'', Operation=CorsEngine.EvaluatePolicy
w3wp.exe Information: 0 : Operation=CorsMessageHandler.SendAsync, Status=200 (OK)
w3wp.exe Information: 0 : Response, Status=200 (OK), Method=POST, Url=http://myhost/myvdir/api/v1/MyCntrllr/MyAction, Message='Content-type='application/json; charset=utf-8', content-length=unknown'
w3wp.exe Information: 0 : Operation=JsonMediaTypeFormatter.WriteToStreamAsync
w3wp.exe Information: 0 : Operation=MyCntrllrController.Dispose

代码:

WhiteListOriginPolicy

public class WhiteListOriginPolicy 
    : CorsPolicy
{
    public WhiteListOriginPolicy()
    {
        AllowAnyHeader = true;
        AllowAnyMethod = false;
        Methods.Add(HttpMethod.Post.ToString());
        Methods.Add(HttpMethod.Options.ToString());
        foreach (var origin in Settings.Default.WhiteListOrigins)
        {
            Origins.Add(origin);
        }
    }
}

WhiteListOrigins 是来自 web.config 文件的 StringCollection

WhiteListOriginPolicyProvider

public class WhiteListOriginPolicyProvider 
    : ICorsPolicyProvider
{
    public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return Task.FromResult((CorsPolicy) new WhiteListOriginPolicy());
    }
}

CorsPolicyProviderFactory

public class CorsPolicyProviderFactory
    : ICorsPolicyProviderFactory
{
    private readonly ICorsPolicyProvider _whiteListOriginsPolicyProvider = new WhiteListOriginPolicyProvider();

    public ICorsPolicyProvider GetCorsPolicyProvider(HttpRequestMessage request)
    {
        return _whiteListOriginsPolicyProvider;
    }
}

WebApiConfig

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        config.EnableSystemDiagnosticsTracing();
        config.SetCorsPolicyProviderFactory(new CorsPolicyProviderFactory());
        config.EnableCors();
        // Web API routes
        config.MapHttpAttributeRoutes();
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{action}",
            defaults: new { action = RouteParameter.Optional }
            );
    }
}

WhiteListOriginPolicyAttribute

我觉得这是多余的,但是用不用都无所谓

public class WhiteListOriginPolicyAttribute
    : Attribute
    , ICorsPolicyProvider
{
    public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return Task.FromResult((CorsPolicy) new WhiteListOriginPolicy());
    }
}

MyCntrllrController

[RoutePrefix("api/v1/MyCntrllr")]
public class MyCntrllrController
    : ApiController
{
    [HttpPost]
    [HttpOptions]
    [WhiteListOriginPolicy]
    [Route("MyAction")]
    public IMyConclusion MyAction([FromBody] Submission submission)
    {
        if (Request.Method == HttpMethod.Options)
        {
            return null;
        }
        if (null == submission)
        {
            var response = new HttpResponseMessage(HttpStatusCode.BadRequest)
            {
                Content = new StringContent("Request content body does not contain recognizable Submission data")
            };
            throw new HttpResponseException(response);
        }
        var engine = new CalcEngine(new DataLocatorService());
        var eligibility = engine.GetEligibility(submission);
        return eligibility;
    }
}

OPTIONS 动词的作用。

请求

OPTIONS http://myhost/myvdir/api/v1/MyCntrller/MyAction HTTP/1.1
Accept: */*
Origin: http://localhose
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type, accept
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Host: myhost
Content-Length: 0
DNT: 1
Connection: Keep-Alive
Pragma: no-cache

回应

HTTP/1.1 400 Bad Request
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Wed, 20 Nov 2013 20:32:03 GMT
Content-Length: 59

{"Message":"The origin 'http://localhose' is not allowed."}

正在使用的 POST 动词。

请求

POST http://myhost/myvdir/api/v1/MyCntrller/MyAction HTTP/1.1
Accept: */*
Origin: http://localhose
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type, accept
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Host: myhost
Content-Length: 121
DNT: 1
Connection: Keep-Alive
Pragma: no-cache
Content-Type: application/json

{"myvalue1":24000,"myvalue2":"2","myvalues3":["24","34"],"myvalue4":0,"myvalue5":"90001","myvalue6":"c0","myvalue7":"16"}

回应

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Wed, 20 Nov 2013 20:32:33 GMT
Content-Length: 460

_omitted_

【问题讨论】:

  • 这感觉像是一种解决方法,但我为停止 POST 所做的是添加一个自定义 AuthorizationFilterAttribute,它从请求中显式提取 Origin 标头,将其与白名单源列表进行比较,并发出 BadRequest如果它不在列表中,则响应。

标签: asp.net-web-api cors


【解决方案1】:

这不是 CORS 的目的。浏览器阻止跨源 Ajax 调用,因此 CORS 将允许目标服务器放宽这些规则。默认情况下,浏览器会阻止调用 JS 获取 POST 的结果,但不会阻止 POST(或 GET)到端点。您需要实施标准授权方法以确保只有允许的客户端才能请求端点。

【讨论】:

  • 谢谢。我的进一步阅读表明,CORS 实际上是为了启用浏览器获得结果(通常被浏览器阻止的跨域资源共享),而不是阻止它做任何事情。所以我的“解决方法”现在感觉不像是一种解决方法,而更像是实际的解决方案。如果我明天还没有更彻底的信息,我会接受你的回答。
  • 请解释如何阻止 POST 或 GET
  • 是的,你是对的——我的措辞并不准确。 CORS 放宽了规则。我更新了我的措辞。这是我几年前写的更多细节:msdn.microsoft.com/en-us/magazine/dn532203.aspx
猜你喜欢
  • 2015-11-18
  • 2015-09-08
  • 2015-09-07
  • 2017-06-07
  • 2018-03-21
  • 2014-05-22
  • 1970-01-01
  • 2018-07-20
  • 2019-03-21
相关资源
最近更新 更多