当前位置: 首页 > Web前端 > HTML

腾讯方面:为什么CORS可以保证安全?为什么只对复杂的请求进行预检?

时间:2023-03-28 17:57:47 HTML

大家好,我是念念!说到CORS,大部分文章都是在讲什么是简单请求,什么是复杂请求,什么是复杂请求预校验的过程。但是如果我问你:CORS为什么要带源,这是为了保证当前站点的安全还是目的服务器的安全?为什么要区分简单请求和复杂请求,只预检复杂请求?本文将重点介绍CORS如何确保安全并阐明这些问题。看完你就知道CORS是什么,为什么。什么是CORS相信每个前端控制台都打印过这样一段话,告诉你:你的跨域请求策略被拦截了!首先要明确一点,CORS的目的不是为了拦截请求,而是让它们可以正常请求。CORS诞生的背景是“同源策略”。这是一个相当严格的规则,它禁止跨源AJAX请求。但是在实际开发中有这样的需求,所以开了一个口子——只要配置好CORS的相应规则,跨域请求就可以正常进行了。这也对应了CORS的名称——“跨域资源共享”,就是在“同源策略”的背景下,允许进行跨域请求。回到上面提到的控制台报错,这不是阻止你跨域请求,而是提醒你:因为你没有按照CORS要求进行配置,所以暂时屏蔽掉。上面已经解释了如何配置CORS。只要按照CORS要求进行配置,就可以突破同源策略的限制。下面将介绍如何配置。这部分不需要前端操心,完全由后端来完成:在响应头中添加一个字段Access-Control-Allow-Origin(允许请求的来源),这个值应该包括前端的来源。例如:请求的后端接口是http://fe_nian,而你在本地开发一个前端项目,运行在8080端口,那么后端会在响应头中添加Access-Control-Allow-Origin:*来允许originhttp://localhost:8080进行跨域请求,因为*代表一切。跨域请求的过程CORS将请求分为简单请求和复杂请求,划分的依据是“是否会产生副作用”。简单贴下定义,满足下面两个条件的简单请求就是请求方式为HEAD/GET/POST,请求体的文件类型只能是form-urlencoded,form-data,text/plain(这样的文章很多,不详细可以看阮一峰-跨域资源分享)对于简单的请求,流程如下:浏览器发起请求,自动将请求的来源添加到服务器供检查;服务器返回数据,返回检查结果,并配置CORS响应头;浏览器检查CORS响应头,如果包含当前源则放行,否则拦截;这里需要注意的是,浏览器拦截的是response,不是request,发送的是跨域请求,服务器响应。只是浏览器屏蔽了而已。对于复杂的请求,整个过程是这样的:浏览器发起预校验请求,带有请求的来源,不包含请求体;服务器返回校验结果并配置CORS头;浏览器发起真实请求;浏览器返回数据;浏览器会检查第2步得到的CORS头,如果不包含当前源,则不会执行后面的第3步和第4步,即不会发起真正的请求。为什么带源码CORS在给开发带来方便的同时,也带来了安全隐患——CSRF攻击。其基本流程如下:用户登录受害网站,将获得的身份凭证保存在浏览器的cookie中。即上图中的流程①②③;用户用同一浏览器打开黑客网站,黑客网站向受害网站服务器发送恶意请求。这时浏览器会自动从cookie中取出身份证明并带上。即上图中的④⑤;受害网站服务器发现有身份证明,成功接受恶意请求;如果严格遵循同源策略,则无法进行第2步的跨域请求,也不会造成危害。因此,CORS策略的心智模型是:所有的跨域请求都是不安全的,浏览器必须将源码带到服务器端进行检查。如果做过服务器端开发的应该知道,服务器端是不存在跨域的,从另外一台服务器获取资源是非常顺利的。因为服务器不像浏览器,将用户凭证存储为“容器”——也就是上面第一步发生的事情,所以它在进行跨域请求时不存在这种风险。为什么只对复杂请求做preflight上面说过,简单请求和复杂请求的划分依据是“是否产生副作用”。这里的副作用指的是对数据库进行修改:使用GET请求获取新闻列表,数据库中的记录不会发生变化,而使用PUT请求修改记录时,数据库中的记录会发生变化。对于简单的请求,浏览器只会在请求头中增加一个origin字段来标识请求的来源;对于非简单的请求,浏览器会先发送预检请求,得到肯定答复后才会发送真正的请求,下面会解释为什么要这样做。可以假设网站被CSRF攻击——黑客网站向银行服务器发起跨域请求,银行安全意识薄弱,只要有登录凭证cookie就可以成功响应:黑客网站发起GET请求,查看受害用户本月的账单。银行的服务器会返回正确的数据,但是影响不大,而且由于浏览器的拦截,黑客最终没有拿到数据;黑客网站发起PUT请求清空受害用户的账户余额。浏览器会先做预检,发现收到的响应没有携带CORS响应头,所以不会发送真正的PUT请求;幸好有预校验机制,否则一旦发送PUT请求,黑客的攻击就得逞了。结论回到开头的两个问题,不难得出答案:对于跨域请求,请求的来源是为了防止CSRF攻击;浏览器的心智模型是:跨域请求是不安全的,CORS机制是为了保证请求目的服务器的安全;根据是否对服务器有副作用来划分简单请求和复杂请求(但由于历史原因,表单POST请求也分为简单请求),预检查机制会拦截不安全的复杂请求,避免危害到服务器,简单的请求通常不会修改服务器的资源,即使危害不大。如果这篇文章对你有帮助,请点个赞,这就是我创作的动力~不如多多关注!