前端必备HTTP技能之跨站资源共享(CORS)技术详解

CORS(Cross-origin resource sharing)是一种安全机制,允许其他域请求获取到当前域中web页面中的限制资源。web页面可以自由的嵌入图片,样式,脚本,iframe,视频等资源,但是由于同源策略的限制,跨域请求会被限制。

CORS定义了一种方式,通过这种方式浏览器和服务器可以互相确定允许跨域请求是否是安全的。这样就比单纯的同源请求有更多的自由度,也可以实现更多的功能,而且也比允许全部的跨域请求更安全。CORS是W3C中的一个推荐标准。

CORS原理
CORS标准介绍了新的HTTP headers,在浏览器和服务器都获得授权的情况下,这些headers给它们提供了一种访问远程URL的方式。尽管服务器可以执行一些验证和授权,但是浏览器也有责任来支持这些headers,遵循限制。

对于AJAX和可以修改数据的HTTP请求方法来说,规范规定浏览器预检查请求,通过请求头中的OPTIONS方法获取服务端支持的请求方法,然后得到服务器的批准之后,使用真实的HTTP请求方法发送真实的请求。服务器也可以通知客户端是否需要随请求发送证书(包括Cookies和HTTP认证数据)。


示意图
示意图

简单示例
当支持CORS的浏览器尝试发起跨域请求时:
1.浏览器发送OPTIONS请求,并在HTTP头中指定Origin,Origin的值是提供父级页面的域。当前域http://www.foo.com中的页面尝试获取域http://www.bar.com中的用户数据时,下面的请求头将会发送给http://www.bar.com域:

Origin:http://www.foo.com

2.服务器可能会有下面的响应:

  • 响应头中的Access-Control-Allow-Origin标识允许那个来源站点。例如:
    Access-Control-Allow-Origin: http://www.foo.com
  • 如果服务器不支持跨域请求会返回错误页面
  • 响应头中的Access-Control-Allow-Origin如果是通配符则表示允许任何域访问:
    Access-Control-Allow-Origin: *

当一个页面或者API是完全公开的,并且可以被任何人或者任意站点上的代码访问时,通配符同源策略是一个好的方法。例如在公共托管服务上的免费可用的Google字体

通配符*意味着服务器不需要请求提供凭证,有意义的HTTP身份验证,客户端的SSL验证,也不允许发送cookies。

注意在CORS架构中,Access-Control-Allow-Origin头是外部web服务器(http://www.bar.com)设置的,而不是源web服务器(http://www.foo.com)设置的。CORS允许外部web服务器授权web应用使用它的服务,不控制web应用访问外部服务。

预检查示例
执行某些类型的跨域ajax请求时,支持CORS的浏览器会插入一个额外的预检查请求来决定是否有权限执行相应的动作。

OPTIONS /
Host: bar.com
Origin: http://foo.com

如果bar.com想要接收这种行为,它可能会回复下面的响应头:

Access-Control-Allow-Origin: http://foo.com
Access-Control-Allow-Methods: PUT, DELETE

Headers
CORS相关的HTTP头如下:

请求头

  • Origin
  • Access-Control-Request-Method
  • Access-Control-Request-Headers

响应头

  • Access-Control-Allow-Origin
  • Access-Control-Allow-Credentials
  • Access-Control-Expose-Headers
  • Access-Control-Max-Age
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Headers

浏览器支持情况
浏览器支持详情可以参考can I use网站上面的统计,点这里查看详情。

历史
跨域支持最早是在2004年的VoiceXML中作为一个杂项提出的,主要是为了支持VoiceXML浏览器可以安全获取跨域数据。机制本质上是通用的,在VoiceXML中没有具体化,随后被分配到一个实现备忘中。然后主要浏览器厂商参与的W3C的WebApps工作组开始把备忘录规范化成W3C工作草案,最后才慢慢变成W3C推荐标准

CORS和JSONP对比
CORS可以作为JSONP模式的一个现代选择。JSONP只支持GET请求,而CORS也支持其他类型的HTTP请求方法。使用CORS,开发者可以正常使用XMLHttpRequest对象发送请求,这种方法处理错误比JSONP方便。从另一方面来说,JSONP可以兼容不支持CORS的老版浏览器。CORS只能被大多数现代浏览器支持。JSONP可能导致XSS问题,而CORS允许站点手动解析响应来确保安全。

做好前端开发必须对HTTP的相关知识有所了解,所以我创建了一个专题前端必备HTTP技能专门收集前端相关的HTTP知识,欢迎关注,投稿。


PS:本文翻译自维基百科,原文地址https://en.wikipedia.org/wiki/Cross-origin_resource_sharing

推荐阅读更多精彩内容