# 目录

为什么有同源策略?

  • 需要解决的问题

CORS跨域请求方案

  • preflight
  • withCredentials
  • 附:高效、优雅地调试CORS实现

为什么有同源策略?

同源策略Same Origin Policy 是一种约定,是浏览器最核心的安全功能:

该策略允许在源自同一站点的页面上运行的脚本在没有特定限制的情况下访问彼此的数据,但阻止脚本访问存储在不同域中的数据。

所谓同源是指域名、协议、端口相同。

同源策略主要是为了安全,如果浏览器没有同源限制,那么:

① 某域下的Cookie等与该域相关的密切数据可以任意读取

② 不同域下DOM任意操作,篡改

③ 恶意网站能随意执行Ajax脚本偷取隐私数据

针对以上第③点:举个栗子:

用户正在访问银行网站B但未注销。然后用户转到另一个站点A,该站点在后台运行一些恶意JavaScript代码,该代码从银行站点B请求数据。由于用户仍然登录银行站点,恶意代码可以执行用户在银行站点B上执行的任何操作。

例如,它可以获得用户上次交易的列表,创建新交易等。这是因为浏览器可以基于银行站点的域向银行站点发送和接收会话cookie。

访问恶意站点的用户以为他访问的站点无法访问银行会话cookie。虽然恶意网站下JavaScript确实无法直接访问银行会话cookie,但它仍然可以通过银行网站的会话cookie向银行网站发送和接收请求。

同源策略在实施中需要解决的问题:

同源策略限制 通过脚本访问不同域的数据,大棒一挥, 关闭了正常访问外部域名数据的可能。
有以下变通方法:
  • 实现CORS (Cross-Origin Resource Sharing)

  • 使用JSONP (JSON Padding)

  • Use postMessage method

  • 建立一个本地代理服务器,这样先同源访问,由代理服务器转发请求

CORS跨域请求方案

CORS是一个服务器允许放松同源策略的W3C标准,服务器可以显式允许同源请求并且拒绝其他的非同源访问。

CORS标准描述了新的HTTP标头,它为浏览器提供了一种仅在获得许可时才能请求远程URL的方法。尽管服务器可以执行某些验证和授权,但浏览器通常负责支持这些标头并遵守它们所施加的限制。

Request headers
  • Origin
  • Access-Control-Request-Method
  • Access-Control-Request-Headers
Response 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

举个橘子:

CORS规范

① 浏览器使用XmlHttpRequest发起跨域Ajax请求,浏览器会自动携带Origin请求

② 服务器有一套自己的的CORS逻辑,这个逻辑会在服务端响应头:Access-Control--*******--中体现

举例: Access-Control-Allow-Origin: */Origin/null // 该响应头会3种可能值

③ 浏览器会遵守Access-Control--*******-- 响应头对应值所施加的限制

GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://foo.example/examples/access-control/simpleXSInvocation.html
Origin: http://foo.exampleHTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2.0.61
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xmlBODY

预检Preflight

对于可以修改数据的Ajax和HTTP请求方法(通常是GET以外的HTTP方法,或者某些MIME类型的POST用法),CORS规范要求浏览器“预检”请求,

使用HTTP OPTIONS请求方法从服务器请求支持的方法(由浏览器发起),然后,在服务器“批准”时,使用实际的HTTP请求方法发送实际请求。

上图描述了浏览器是是怎样决定使用【简单请求】还是 【预检XHR请求】

const invocation = new XMLHttpRequest();
const url = 'http://bar.other/resources/post-here/';
const body = '<?xml version="1.0"?><person><name>Arun</name></person>';function callOtherDomain(){if(invocation){invocation.open('POST', url, true);invocation.setRequestHeader('X-PINGOTHER', 'pingpong');invocation.setRequestHeader('Content-Type', 'application/xml');invocation.onreadystatechange = handler;invocation.send(body); }
}......
// 以上使用POST 发送了一个xml,同时自定义了一个request header: X-PINGOTHER, 该跨域请求必定会触发浏览器预检行为

携带凭据跨域

默认情况下,浏览器在XMLHttpRequest请求中不会发送凭据 (凭据包括HTTP cookies 和 Http认证信息比如 Authorization头)。

访问的外站API需要授权,这时就涉及携带凭据跨域:

const invocation = new XMLHttpRequest();
const url = 'http://bar.other/resources/credentialed-content/';function callOtherDomain(){if(invocation) {invocation.open('GET', url, true);invocation.withCredentials = true;   // 该标记设定在XMLHttpRequest中发送凭据invocation.onreadystatechange = handler;invocation.send(); }
}

GET /resources/access-control-with-credentials/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://foo.example/examples/credential.html
Origin: http://foo.example
Cookie: pageAccess=2HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:34:52 GMT
Server: Apache/2.0.61 (Unix) PHP/4.4.7 mod_ssl/2.0.61 OpenSSL/0.9.7e mod_fastcgi/2.4.2 DAV/2 SVN/1.4.2
X-Powered-By: PHP/5.2.6
Access-Control-Allow-Origin: http://foo.example    // 当响应的是一个携带凭据的请求,服务端必须为Access-Control-Allow-Origin响应头指定一个Origin,而不能再用 * 通配符。
Access-Control-Allow-Credentials: true
Cache-Control: no-cache
Pragma: no-cache
Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT  // 设置新的Cookie
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 106
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain[text/plain payload]

需要注意:

  1. 以上携带请求凭据跨域,若响应头Access-Control-Allow-Origin被指定为“*”, 请求将报错; 也就是说 在携带凭据跨域的时候,服务器响应头不允许使用囫囵吞枣的* 通配符。

  2. 虽然浏览器提示报错;实际上浏览器会取得Response,但是浏览器会遵守CORS规范阻止你的代码访问响应体。

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSNotSupportingCredentials。
https://stackoverflow.com/questions/46737291/cors-error-but-data-is-fetched-regardless
The browser itself runs into no error in getting the response. But your code runs into an error because it’s trying to access a response that’s not there — because the browser isn’t exposing the response to your code.

附:一种高效、优雅地调试CORS实现的方法

https://stackoverflow.com/questions/12173990/how-can-you-debug-a-cors-request-with-curl/12179364#12179364

CORS规范很大程度体现了服务端对资源的安全策略, 作为后端开发人员,调试CORS规范不是一个简单的事情:

直观上:需要搭建跨域服务器、构建AJAX脚本请求。

使用Curl命令来调试CORS规范, 好嗨哟。
Curl是一个利用URl规则在命令行下工作的文件传输工具,可以说是一款强大的http命令行工具。
https://curl.haxx.se/docs/manpage.html

下面curl命令演示了在某网站跨域Post请求外站api时 触发的预检options请求:
curl "https://A.com/api/3.0/drilldown/query" -X OPTIONS -H "Access-Control-Request-Method: POST" -H "Origin: http://www.example.com.cn" -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36" -H "Access-Control-Request-Headers: content-type"  --verbose 

-X 请求动词

-H 指定请求头

--verbose 输出详细内容

结果如下:

以上从为什么?怎么做?更高效的完成? 三方面讲述了CORS,希望对大家有所帮助。

作者:JulianHuang

感谢您的认真阅读,如有问题请大胆斧正;觉得有用,请下方或加关注。

本文欢迎转载,但请保留此段声明,且在文章页面明显位置注明本文的作者及原文链接。

转载于:https://www.cnblogs.com/JulianHuang/p/10337980.html

看后端程序员调试CORS的姿势相关推荐

  1. 后端程序员的前端工具

    后端程序员的前端工具 在总结监控系统时,其中有一点:将API 接口开发转变为SQL 查询,支持sql算子.这样后端开发工程师就不用疲于奔命提供查询服务了.听说阿里巴巴的产品工程师也要学习SQL语句,为 ...

  2. 每日一皮:资深程序员调试代码的样子...

    这就是资深程序员调试代码的样子 也就是说闭着眼睛也能处理bug 往期推荐 每日一皮:产品和开发在线上吵了许久... 每日一皮:软件从业人员表情图... 每日一皮:强大的sudo ... 每日一皮:周六 ...

  3. [转]后端程序员必备:书写高质量SQL的30条建议

    以下文章来源于捡田螺的小男孩 ,作者捡田螺的小男孩 转载:<后端程序员必备:书写高质量SQL的30条建议> 前言 本文将结合实例demo,阐述30条有关于优化SQL的建议,多数是实际开发中 ...

  4. 后端程序员生产力工具合集

    后端程序员除了写代码,也难免要写设计文档,画各种图.因此掌握各种生产力工具,是很有必要的,可以达到事半功倍的效果. 下面结合楼主亲身体验,推荐一些生产力工具,欢迎探讨和补充. 主要分成几大类: 画图 ...

  5. Java后端程序员1年工作经验总结

    java后端1年经验和技术总结(1) 1.引言 毕业已经一年有余,这一年里特别感谢技术管理人员的器重,以及同事的帮忙,学到了不少东西.这一年里走过一些弯路,也碰到一些难题,也受到过做为一名开发却经常为 ...

  6. 前端程序员和后端程序员有什么不同?我来告诉你薪资待遇差多少

    作为一个程序员,我发现后端程序员和前端程序员有很大的不同.后端程序员主要关注的是处理看不见的部分,如服务器.数据库.API等等.而前端程序员主要关注的是展现的部分,如网页的设计.交互和用户体验等等. ...

  7. 后端程序员必须要懂的MySQL数据库

    整体结构图 和其它数据库相比,MySQL 有点与众不同,它的架构可以在多种不同场景中应用并发挥良好作用.主要体现在存储引擎的架构上,插件式的存储引擎架构将查询处理和其它的系统任务以及数据的存储提取相分 ...

  8. 入职后端程序员的一些心得

    入职后端程序员的一些心得 本来打算上床睡觉,但是想到这段时间的所作所为,有许多值得反省的地方.曾子有言:吾日三省吾身,我虽然做不到曾子的程度,不过也尽量在工作之余好好反思,争取少犯错误,提高工作效率. ...

  9. 【Vue】Java后端程序员也必须掌握的前端框架(下)

    Vue基础 前言 十一.自定义事件内容分发 十二.vue-cli 1.安装 vue-cli 2.第一个 vue-cli 应用程序 3.Vue-cli目录结构 十三.Vue的Webpack 十四.vue ...

最新文章

  1. 1.2 什么是神经网络-深度学习第一课《神经网络与深度学习》-Stanford吴恩达教授
  2. 银行祖传系统重构实例:创立12年,只支持Python 2,跑着500多个应用程序
  3. python中常用的推导(字典推导和列表推导)
  4. linux可以打开浏览器嘛,Linux下怎样可以打开浏览器
  5. [激励机制]浅谈内部竞争——如何让你的员工玩命干活?
  6. “约见”面试官系列之常见面试题之第一百零三篇之vue-router实现路由懒加载(建议收藏)
  7. java构造器_Java类加载的过程
  8. Python原创第十篇~字符串
  9. Python实战从入门到精通第十二讲——给函数参数增加元信息
  10. mysql6.0_MySQL6.0安装
  11. win7 linux win7 无法启动,ubuntu 和win7双系统安装后win7无法启动解决办法
  12. 洛谷oj——P1316 丢瓶盖【二分】
  13. 威纶通触摸屏直接与台达变频器进行MODBUS RTU通信的具体方法(图文)
  14. 2020-1024=996(程序员节)
  15. java 分析内存_Java 内存查看与分析
  16. Window平台的eclipse连接linux的hadoop集群
  17. html实现简易音乐播放器
  18. 双相障碍快速循环发作的治疗:证据回顾 | 文献述评
  19. 永磁电机风力发电机原理及并网实验系统QY-TF18
  20. 1.《小狗钱钱》读书笔记

热门文章

  1. 四年级计算机笔试题,四年级计算机考试卷.doc
  2. java网络接口_java网络编程之识别示例 获取主机网络接口列表
  3. 长沙理工大学计算机考研难吗,长沙理工大学考研难吗?一般要什么水平才可以进入?...
  4. file获取文件后缀_Python 工匠:高效操作文件的三个建议
  5. 计算机桌面程序名,深度技术win7旗舰版电脑桌面图标只显示名称了怎么办
  6. 声音均衡器怎么调好听_汽车10段音效最佳设置,手把手教你调节车载音响均衡器...
  7. HTML+CSS+JS实现 ❤️圣诞抓礼物小游戏❤️
  8. HTML+CSS+JS实现 ❤️ 粒子倒计时特效❤️
  9. zookeeper 密码_Dubbo、ZooKeeper介绍
  10. 用python做频数分析_使用Python进行描述性统计