聊一聊我对跨域的理解和最佳实践

2023-05-29 0 948

布吕马是后端合作开发中两个非常常用的难题,尤其是随着白眉林应用领域(Single Page Application, SPA)的蓬勃发展,其间端分立合作开发和布署,后端在邻近地区合作开发和布署的过程中单厢遭遇着布吕马难题。他们再度谈谈布吕马这个热门话题,以及项目中对布吕马的许多成功经验,希望带来许多捷伊斩获。

甚么是布吕马

具体来说他们需要了解下甚么是相混思路,MDN 中是这样如是说的:

相混思路是应用领域程序的两个重要安全可靠思路,它用于管制两个源的文档格式或者它读取的JAVA如何能与另两个源的天然资源进行操作方式。它能协助隔绝蓄意文档格式,减少可能被反击的传播方式。

从该文他们获知,相混思路是应用领域程序的安全可靠思路,源(Origin)是推论是否满足用户相混思路的条件。他们常说的布吕马,精确而言应该是跨源,目地是倍受相混思路的管制去操作方式另两个源的天然资源。比如当他们在邻近地区合作开发时,源是 http://localhost:3000,而服务器端USB的门牌号是 https://api.feishu.cn,这时透过 fetch 出访USB就会造成布吕马。

相混思路源于于应用领域程序,但若在非应用领域程序的自然环境下,一般是没有相混思路管制的。比如在 Node.js 中,他们能允诺任一的邮箱并得到结果。因此如前所述 Node.js 的服务器端能间接布吕马出访天然资源。

当然他们也能停用应用领域程序的相混思路,停用后应用领域程序自然环境下也能间接布吕马。以 Chrome 为例,透过给 Chrome 增加开启模块:

$ /path/to/chrome.app –disable-web-security

方可停用。停用后应用领域程序会有安全可靠风险,建议再加在邻近地区合作开发上

源由协定、搜索引擎(精确而言是Teredo,因为除了搜索引擎也能是 IP)、freenode协力决定,二者完全相同的两个 URL 会被认为是相混。举几个范例:

https://www.bytedance.com 和 https://jobs.bytedance.com,搜索引擎相同,不相混http://www.bytedance.com 和 https://www.bytedance.com,协定相同,不相混http://localhost 和 http://localhost:8080,路由器相同(80 和 8080),不相混

特别的,当他们间接关上两个 HTML 文档时,使用的是 file 协定,允诺 HTTP USB时协定相同,会造成布吕马。

源是容许被有效用的修正,应用领域程序提供了 API 能Jhunjhunun搜索引擎下的源修改为父搜索引擎的源,比如他们在https://open.feishu.cn 下执行:

document.domain = feishu.cn;

这时页面的源就变成了 https://feishu.cn满足用户相混思路,我们就能间接出访父搜索引擎下的天然资源。如果修正为非父搜索引擎(如http://bytedance.com),应用领域程序会报错。

相混思路控制不相混之间的操作方式,这些操作方式通常分为三类:

天然资源嵌入:一般是被容许的。比如 <script>、<iframe> 引入天然资源写操作方式:一般是被容许的。比如链接、重定向以及表单提交,满足用户特定条件的 HTTP 允诺不容许读操作方式:一般是不被容许的。比如 XMLHttpRequest 和 Fetch API 发起 GET 允诺

根据这个分类,他们来重点讨论几种情况:

<script> 是天然资源嵌入倍受相混思路控制,JSONP 就是借助这一特性实现的布吕马<form> 是天然资源写入倍受相混思路控制,因读取天然资源,受相混思路控制,允诺返回的内容在不相混的情况下他们是读不到的当发起 HTTP POST 允诺修正天然资源,一般是倍受相混思路控制的(称为简单允诺),天然资源是容许被修正;而对于非简单允诺,受相混思路控制,天然资源不容许修正

需要特别说明的是:

HTTP GET 读取天然资源虽然受相混思路控制,但允诺是成功发送的,只是应用领域程序管制了允诺返回的内容不给他们而是抛出了错误HTTP POST 写入天然资源时,简单允诺也是避免天然资源被修正,因此受相混思路控制。下面课堂教学部分会详细讨论如何容许布吕马。WebSocket 倍受相混思路控制

简单允诺必须满足用户以下条件:

HTTP 方法是:GET、POST 或 HEAD除了被应用领域程序自动设置的字段(比如 Connection、User-Agent),允诺头只容许以下字段:Accept Accept-Language Content-Language Content-Type:只容许值为 text/plain、multipart/form-data、application/x-www-form-urlencodedRange:只容许简单的范围标头值,如 bytes=256- 或 bytes=127-255

不满足用户上述条件的即为非简单允诺。比如当他们在允诺头增加 X-JWT-Token 或 Content-Type: application/json 时,这个允诺就是非简单允诺。

为什么需要相混思路

上面他们说了,相混思路是两个安全可靠思路。如果相混思路被停用,个人信息将会有安全可靠风险,比如:

修正天然资源

布吕马的最差课堂教学

那么他们如何才能布吕马呢?应用领域程序在相混思路的基础上,提出一种能安全可靠的布吕马机制称为跨源天然资源共享(Cross Origin Resource Sharing,CORS)。当然在这个机制发布之前,也有 JSONP 等满足用户应用领域程序安全可靠机制的布吕马方案,本文不具体讨论。

CORS 的使用很简单,服务器端(即被允诺的天然资源)在响应头中增加:

Access-Control-Allow-Origin: https://www.bytedance.com

方可,其中的值表示容许布吕马出访的源,这时 https://www.bytedance.com就能出访这个服务器的天然资源。他们能看出,允诺是成功发送并得到响应的,应用领域程序才能拿到 Access-Control-Allow-Origin 响应头并推论是否能布吕马(先允诺再推论)。那么对于非简单允诺,为了避免天然资源被意外修正,是需要先推论是否能布吕马再发起修改允诺的(先推论再允诺),这时应用领域程序就会先发起两个预检允诺(HTTP 方法为 OPTIONS),拿到服务器端返回的 Access-Control-Allow-Origin 并推论,满足用户容许布吕马的话再发起真实允诺。

如果他们无法修正服务器端呢?能实现两个他们可控的代理服务器端,增加容许布吕马响应头或间接同域,解决布吕马难题,比如透过 Nginx、Charles 或 webpack-dev-server 代理。

下面他们来讨论项目中几种常用的布吕马场景和最差课堂教学:

布吕马允诺需要携带 Cookie

XMLHttpRequest 和 Fetch API 在发起布吕马允诺时默认是不携带服务器端所在源的 Cookie,这样影响到了服务器端的用户身份鉴别。他们需要增加模块,比如:

const xhr = new XMLHttpRequest(); xhr.withCredentials = true;

fetch(url, { credentials: include, });

应用领域程序才会携带 Cookie,同时服务器端需要返回响应头:

Access-Control-Allow-Credentials: true

应用领域程序才会正常将响应内容返回给他们,否则会抛出错误

容许白名单内的源布吕马允诺

当有多个源需要容许布吕马出访时,服务器端能配置

Access-Control-Allow-Origin: *

容许所有源布吕马出访,但开放范围太大有一定的安全可靠隐患,同时这种情况下应用领域程序不容许携带 Cookie。他们需要对源精细化的控制,但 Access-Control-Allow-Origin 不容许设置多个源。他们能透过允诺头 Origin 加白名单推论的方式,动态返回 Access-Control-Allow-Origin 的值解决。

Origin 是布吕马允诺时应用领域程序自动携带的值,表示允诺的源,他们在服务器端定义两个白名单推论这个源是否在白名单中,如果在则返回 Access-Control-Allow-Origin 的值等于允诺头的 Origin。以 express 为例代码如下:

const whiteList = [https://www.bytedance.com, https://jobs.bytedance.com]; app.get(/path/to/api, (request, response) => { const { origin } = request.headers; if (whiteList.includes(origin)) { response.header(Access-Control-Allow-Origin, origin); response.header(Access-Control-Allow-Credentials, true); } });

包括:

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

ogID 用于记录每次允诺的 logID,他们需要让服务器端返回响应头:

Access-Control-Expose-Headers: X-TT-LogID

前面他们了解到,非简单允诺会先发起预检允诺以检查是否容许布吕马,因此需要两次 HTTP 允诺才能完成这次操作方式。对于他们已知是读操作方式的允诺,他们能尽量满足用户简单允诺的条件以减少预检允诺,从而减少允诺时间。

一般而言,他们需要注意的地方如下:

读取天然资源时尽量使用 GET 或 POST 允诺对于 POST 允诺且需要透过 body 传递 JSON 数据时,Content-Type 使用 text/plain 而不是 application/json,同时服务器端也需要支持将 text/plain 解析成 JSON对于其它需要允诺携带的信息,尽量放在允诺模块中而不是自定义允诺头,因为额外的允诺头也会导致变成非简单允诺,比如 JWT 的 X-JWT-Token

CDN 天然资源也需要容许布吕马

如果他们接入了 Sentry 或 Perfsee 等后端监控平台并需要监控站点的 JS JAVA错误,且这些 JS JAVA是布署在 CDN 服务器上,由于 CDN 和他们的站点往往不相混,应用领域程序对于不相混的 <script> 天然资源嵌入不会返回具体的错误信息(读取错误信息属于读操作方式受相混思路控制),这样监控平台收集到的错误信息不完整,对定位难题带来了负面影响。

他们需要让 CDN 服务器也返回 Access-Control-Allow-Origin 头容许他们的源,同时所有引入 JS 的 <script> 需要增加 crossorigin 属性:

<script src=“/path/to/cdn” crossorigin=“anonymous”></script>

总结

他们从三个角度讨论了布吕马是甚么、为甚么需要相混思路以及布吕马的解决方案和课堂教学,重点总结如下:

相混思路是应用领域程序的安全可靠思路,Node.js 自然环境没有布吕马管制应用领域程序的相混思路透过开启模块 disable-web-security 能停用透过协定、搜索引擎、freenode三元组推论相混透过 document.domain 能有效用的修正源简单允诺与非简单允诺的区别,非简单允诺会先发起预检允诺相混思路保证了应用领域程序的安全可靠性布吕马透过增加响应头 Access-Control-Allow-Origin 解决,也能借助代理实现布吕马的许多最差课堂教学:布吕马允诺透过 Access-Control-Allow-Credentials 携带 Cookie透过允诺头 Origin 容许白名单内的源布吕马允诺透过

如果有其它关于布吕马的最差课堂教学,欢迎分享

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务