在ASP.NET 5应用程序中的跨域请求功能详解什么是“同域”添加CORS包在应用程序中配置CORSCORS策略选项跨域请求中的凭据设置先行请求的过期时间CORS是怎么样工作的先行请求

浏览器安全阻止了一个网页中向另外一个域提交请求,这个限制叫做同域策咯(same-origin policy),这组织了一个恶意网站从另外一个网站读取敏感数据,但是一些特殊情况下,你需要允许另外一个站点跨域请求你的网站。

跨域资源共享(CORS:Cross Origin Resources Sharing)是一个W3C标准,它允许服务器放宽对同域策咯的限制,使用CORS,服务器可以明确的允许一些跨域的请求,并且拒绝其它的请求。CORS要比JSONP要相对安全而且更加灵活,这一个章节主要讲述怎么在你的ASP.NET 5应用程序中开启CORS。

什么是“同域”

两个URL含有同样的协议、主机地址和端口号即为同域,或者称为同源。

以下两个URL即为同域

下文中的URL都不是同域

注意:IE在判断同域时忽略了端口号

添加CORS包

在项目的project.json文件中,添加以下内容

"dependencies": {
    "Microsoft.AspNet.Cors": "1.0.0-beta6"
  },

在应用程序中配置CORS

这一节展示如何配置CORS,首先,添加CORS服务,在Startup.cs中添加以下内容:

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors();
}

下一步,配置跨域规则,使用CorsPolicyBuilder类,有两种方法来配置,第一种,调用UseCors方法并使用lambda表达式:

public void Configure(IApplicationBuilder app)
{
    app.UseCors(builder =>
        builder.WithOrigins("http://example.com"));
}

稍后将详细解析所有的配置细节,现在只需要知道在这个示例中,这个规则仅允许从http://example.com的跨域请求。

注意这个CorsPolicyBuilder有一个流式的API,所以你可以这样链式调用方法:

app.UseCors(builder =>
    builder.WithOrigins("http://example.com")
           .AllowAnyHeader()
    );

第二种方式你首先定义一或多个CORS策咯,然后在运行时使用name选择策咯:

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors();
    services.ConfigureCors(options =>
    {
        options.AddPolicy("AllowSpecificOrigin",
            builder => builder.WithOrigins("http://example.com"));
    });
}

public void Configure(IApplicationBuilder app)
{
    app.UseCors("AllowSpecificOrigin");
}

这里定义了一个名为AllowSpecificOrigin的CORS规则,运行时传入了这个名字给UseCors方法。

CORS策略选项

这一节介绍在配置CORO策略时的若干个选项。

设置允许的域

允许一或多个指定的域:

options.AddPolicy("AllowSpecificOrigins",
builder =>
{
    builder.WithOrigins("http://example.com", "http://www.contoso.com");
});

允许所有的域:

options.AddPolicy("AllowAllOrigins",
    builder =>
    {
        builder.AllowAnyOrigin();
    });

在允许所有域之前需要仔细考虑,这将意味着任何web站点都将可以通过AJAX请求调用你的应用。

设置允许的HTTP方法

指定哪些HTTP方法允许访问资源:

options.AddPolicy("AllowSpecificMethods",
    builder =>
    {
        builder.WithOrigins("http://example.com")
               .WithMethods("GET", "POST", "HEAD");
    });

允许所有的HTTP方法:

options.AddPolicy("AllowAllMethods",
    builder =>
    {
        builder.WithOrigins("http://example.com")
               .AllowAnyMethod();
    });

这将影响先行请求和Access-Control-Allow-Methods请求头。

设置允许的请求头

一个CORS先行请求也许包含了Access-Request-Headers头,列出应用程序的HTTP请求头。

指定允许的请求头到白名单:

options.AddPolicy("AllowHeaders",
    builder =>
    {
        builder.WithOrigins("http://example.com")
               .WithHeaders("accept", "content-type", "origin", "x-custom-header");
    });

允许所有的请求头:

options.AddPolicy("AllowAllHeaders",
    builder =>
    {
        builder.WithOrigins("http://example.com")
               .AllowAnyHeader();
    });

所有的浏览器对于设置什么Access-Control-Request-Headers的表现并不完全一致,所以加入你设置除了“*”意外的任何其他的头,你应该至少包含“accept”、“content-type”、“origin”,然后加上你想要支持的请求头。

设置暴露的响应头

默认情况下,浏览器并不暴露所有的响应头,默认可用的响应头如下所示:

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

CORS可以通过简单的方法调用,让其他的响应头可用:

options.AddPolicy("ExposeResponseHeaders",
    builder =>
    {
        builder.WithOrigins("http://example.com")
               .WithExposedHeaders("x-custom-header");
    });

跨域请求中的凭据

凭据需要在CORS中做特殊的处理,默认情况下,浏览器在跨域请求中不发送任何凭据。凭据包含除HTTP认证方案之外的cookies。为了在跨域请求中发送凭据,客户端需要用设置XMLHttpRequest的withCredentials属性为true:

var xhr = new XMLHttpRequest();
xhr.open('get', 'http://www.example.com/api/test');
xhr.withCredentials = true;

在jQuery中:

$.ajax({
    type: 'get',
    url: 'http://www.example.com/home',
    xhrFields: {
        withCredentials: true
    }

同样,服务器端也必须允许凭证:

options.AddPolicy("AllowCredentials",
    builder =>
    {
        builder.WithOrigins("http://example.com")
               .AllowCredentials();
    });

现在,HTTP响应将会包含一个Access-Control-Allow-Credentials头,告诉浏览器,服务端允许在跨域请求中包含凭证。

假如浏览器发送凭据,但是请求不包含一个有效的Access-Control-Allow-Credentials头,浏览器将不会在应用程序中暴露这个响应,并且AJAX请求将出错。

在允许凭证时候要相当注意,它意味着一个它域的网站在用户不知情的情况下将可以发送一个登陆成功用户的凭据给你的应用程序。CORS还规定如果允许凭证存在,那么将域设置为“*”是无效的。

设置先行请求的过期时间

Access-Control-Max-Age头指定了先行请求的响应可以缓存的时间。设置这个头:

options.AddPolicy("SetPreflightExpiration",
    builder =>
    {
        builder.WithOrigins("http://example.com")
               .SetPreflightMaxAge(TimeSpan.FromSeconds(2520));
    });

CORS是怎么样工作的

这一节将介绍在HTTP消息级别CORS请求中发生了什么。这对理解CORS如何工作非常重要,进而让你可以正确的配置自己的CORS策略,分析你的应用程序为什么不像预期的那样工作。

CORS规定提出了几个新的HTTP头来打开跨域请求。假如你的浏览器支持CORS,它将会自动的为设置跨域设置请求头,你不需要在Javascript中做任何特殊的处理。

下文是一个跨域请求的示例,Origin头设置了哪个域发出请求的信息:

GET http://myservice.azurewebsites.net/api/test HTTP/1.1
Referer: http://myclient.azurewebsites.net/
Accept: */*
Accept-Language: en-US
Origin: http://myclient.azurewebsites.net
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Host: myservice.azurewebsites.net

假如服务器允许这个请求,它将设置一个Access-Control-Allow-Origin头,这个值和请求的Origin值匹配或者是一个*通配符,代表所有的域都是被允许的:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/plain; charset=utf-8
Access-Control-Allow-Origin: http://myclient.azurewebsites.net
Date: Wed, 20 May 2015 06:27:30 GMT
Content-Length: 12

Test message

假如响应不包含Access-Control-Allow-Origin头,AJAX请求就会失败,但是如果浏览器不允许这个请求,即使服务器翻译一个成功的响应,浏览器也不会正确的使用这个响应内容。

先行请求

一些CORS请求中,浏览器在发送真实的请求资源的请求之前,发送一个附加的请求叫做“preflight request”(本文中的先行请求),在以下条件都满足的情况下,浏览器可以忽略这个先行请求:

  • 请求方法是GET、HEAD或者POST
  • 应用程序除了Accept-Language, Content-Language, Content-Type和 Last-Event-ID以为不设置任何其他请求头
  • Content-Type头是以下中的一个:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

设置在头中的规则是通过应用程序调用XMLHttpRequest的setRequestHander方法来应用的,规则不应用浏览器自己的头,例如User-Agent、Hosts、Content-Length。

以下是一个先行请求的示例:

OPTIONS http://myservice.azurewebsites.net/api/test HTTP/1.1
Accept: */*
Origin: http://myclient.azurewebsites.net
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: accept, x-my-custom-header
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Host: myservice.azurewebsites.net
Content-Length: 0

先行请求使用HTTP OPTIONS方法,它包含两个特殊的头:

  • Access-Control-Request-Method:在真正请求中将会被使用的HTTP方法
  • Access-Control-Request-Headers::设置在真正请求中的头的列表(同样不包含浏览器自己的请求头)

下文中是一个示例,并且假设服务端允许请求:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 0
Access-Control-Allow-Origin: http://myclient.azurewebsites.net
Access-Control-Allow-Headers: x-my-custom-header
Access-Control-Allow-Methods: PUT
Date: Wed, 20 May 2015 06:33:22 GMT

响应包含一个Access-Control-Allow-Methods头,它列出了允许的方法,还有一个附加的Access-Control-Allow-Headers头,列出了允许的请求头,如果先行请求成功,浏览器随即发送上文所叙的真正的请求。

原文地址:http://docs.asp.net/en/latest/security/cors.html

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏不止是前端

Vue:前后端数据联调

3419
来自专栏技术小黑屋

Refused to Execute Script From Because Its MIME Type (Text/plain) Is Not Executable, and Strict MIME

今天又与这个问题相遇了,Orz,还是研究一下解决方法和出现原因吧。 刚刚在github上传了一个js文件,想让这个文件被其他网页引用,于是贴出了这个文件的ra...

541
来自专栏Web项目聚集地

什么是跨域?解决方案有哪些?

同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同...

652
来自专栏Ryan Miao

Javascript跨域后台设置拦截

子域名之间互相访问需要跨域 结论放在开头: 服务端必须设置允许跨域 客户端带cookie需要设置withCredentials 无论服务端是否允许跨域,该req...

2618
来自专栏云瓣

跨域二三事

更好的阅读体验 跨域是日常开发中经常开发中经常会接触到的一个重难点知识,何不总结实践一番,从此心中对之了无牵挂。 同源策略 之所以会出现跨域解决方案,是因为同...

34210
来自专栏互扯程序

跨域请求方案 终极版

现在是资源共享的时代,同样也是知识分享的时代,如果你觉得本文能学到知识,请把知识与别人分享。

953
来自专栏纯洁的微笑

springboot(十八):使用Spring Boot集成FastDFS

上篇文章介绍了《如何使用Spring Boot上传文件》,这篇文章我们介绍如何使用Spring Boot将文件上传到分布式文件系统FastDFS中。 这个项目会...

3284
来自专栏恰同学骚年

.NET Core微服务之基于Ocelot+IdentityServer实现统一验证与授权

  这里,假设我们有两个客户端(一个Web网站,一个移动App),他们要使用系统,需要通过API网关(这里API网关始终作为客户端的统一入口)先向Identit...

522
来自专栏.NET开发者社区

支持Ajax跨域访问ASP.NET Web Api 2(Cors)的简单示例教程演示

随着深入使用ASP.NET Web Api,我们可能会在项目中考虑将前端的业务分得更细。比如前端项目使用Angularjs的框架来做UI,而数据则由另一个Web...

1919
来自专栏安恒网络空间安全讲武堂

CSP总结及CTF实例分析

本文作者:HeartSky 最近各大比赛中 CSP 绕过的题目突然多了起来,自己也尝试着总结下 What is CSP? > The new Content-S...

4476

扫描关注云+社区