bug现场谜之总不能告诉客户你要按F12(打开控制台)吧?(跨域详解)

2023-01-22 0 365

bug现场谜之总不能告诉客户你要按F12(打开控制台)吧?(跨域详解)

产品目录

1. bug当晚情形2. 试著查案3. 布吕马简述3.1 何为草同域(相混)?3.2 何为布吕马(布吕马是不是出现?)3.3 布吕马有甚么安全可靠难题?3.4 何为应用程序相混思路(same-origin policy)3.5 何为CORS(布吕马统计数据共享)?3.6 “单纯”和“繁杂”布吕马允诺心灵心路历程4. 归纳提及预览历史记录有关该文所推荐

1. bug当晚情形

当晚三套控制系统,集成同一sizes登入。当中两个控制系统重定向到除此之外两个控制系统时应用程序会创下三次。

讶异关上F12,难题就无法Cadours。

2. 试著查案

关上控制面板难题就化解了?啊怪异!可能将是控制面板关上后,动态文档在应用程序端无须内存导致的。

关上F12明令禁止控制面板Network –> Disable cache增设,居然难题能Cadours,后端js的允诺的确是内存的。

推断三次创下其原因:后端jsservice ticket,再次登入后,再度允诺职权统计数据USB(第三次允诺创下),网页获得成功展现。

笔者对应用程序的行为不熟,这里只是猜测。

笔者控制系统sizes登入实现的CASUSB,所以应用session过期或者失service ticket票据。

应用程序创下三次fiddler抓包如图:

bug现场谜之总不能告诉客户你要按F12(打开控制台)吧?(跨域详解)

第一次异步允诺后,由于没有职权,302重定向访问sizes登入服务。这里控制面板会提示布吕马允诺,布吕马在布吕马详解部分详细介绍。

后端明确说了,不是后端的难题,化解不了。

笔者公司的后端就是硬气。

在后台处理,后台是springboot项目,增加配置:

spring: resources: cache: cachecontrol: max-age: 0 复制代码

后端文档不会内存,难题化解。

禁用内存后,不会出现地址栏创下三次现象,fiddler抓包如图:

bug现场谜之总不能告诉客户你要按F12(打开控制台)吧?(跨域详解)

难题化解了,笔者对那个布吕马的报错产生了兴趣。之前也看过不少布吕马的该文,始终对布吕马云里雾里。春节找出收藏的布吕马该文,好好研读了一下,有所获,赶紧借此文分享出来。

3. 布吕马简述

web开发,工作中肯定接触过如下应用程序控制面板报错:

No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

允诺的布吕马资源responseheader中没有Access-Control-Allow-Origin信息。

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at example.com/

应用程序相混思路明令禁止读取布吕马资源。

Access to fetch at ‘example.com’ from origin ‘http://localhost:3000’ has been blocked by CORS policy.

在域http://localhost:3000下访问域https://example.com资源被明令禁止。

了解后面的内容后,就会明白这些报错的真正含义,也就能处理布吕马难题了。

3.1 何为草同域(相混)?

相同协议(http、https)相同主机名/ip(127.0.0.1、localhost、google.com)相同端口(80、443、8080)

满足三个条件是相混,否则就是不同的域。

注意:localhost主机名虽然在网络层最终会解析为127.0.0.1,但是对于应用程序相混思路来说,localhost127.0.0.1是不同的主机名,二者不同则为布吕马。

3.2 何为布吕马(布吕马是不是出现?)

1989诞生的World Wide Web最初的html只有纯文本。

世界上第两个web网页,只包含纯文本和超链接。

1993年引入<img>标签,在html渲染时允许加载图片资源,这样纯文本中就可以展现图片。像这样在html中允许加载子资源(subresource)的tag还有:

<ifame><link><form><audio><video><script>

诚如上面html标签语义,所谓的“子资源(subresource)”就是例如表单、文档、音视频、脚本等外部资源。

当两个域中包含有上面taghtml渲染时,就会加载subresource,当这个subresource和当前域不相混时,布吕马允诺就出现了。例如,在两个域中xmlhttprequestajax)允诺除此之外两个域的USB时就是布吕马允诺。

3.3 布吕马有甚么安全可靠难题?

两个域中加载另两个域的文档、音视频、脚本等subresource时,大部分情形不会产生甚么安全可靠难题,但是有一些情形如果不做限制,就存在安全可靠隐患。

例如两个域中提供了基于cookie/session权鉴的发送邮件USB,该域允cookie后任意调用发送邮件USB攻击网站。

可能将有同学疑问:发送邮件USB如果需要权鉴认证才能获得成功调用,别人没有认证信息如何能获得成功调用呢?

实际上用户在应用程序端完成登入后,用户信息就存储在应用程序端(cookie),这时关上恶意网站就有可能将被恶意脚本携带用户信息完成攻击。

3.4 何为应用程序相混思路(same-origin policy)

既然布吕马允诺有安全可靠的难题,应用程序端就做了有关限制,称之为“应用程序相混思路”。

相混思路阻止读取布吕马允诺得到的资源。

这是广义的两个定义,实际上应用程序针对不同subresource有不同的限制思路,下面有做详细说明。

同源思路在1995年网景应用程序2.02中引入,最开始是为了保护布吕马DOM而设计的。

布吕马允诺有三种形式:

布吕马写(Cross-origin writes)布吕马内嵌(Cross-origin embeds)跨域读(Cross-origin reads)

相混思路的规则定义如下:

<ifame>:布吕马内嵌允许(需要合适的X-Frame-Options)。<link>:布吕马内嵌允许(需要合适的Content-Type)。<form>:布吕马写允许。<audio>:布吕马内嵌允许。<video>:布吕马内嵌允许。<script>:布吕马内嵌允许,某些api的调用可能将会被明令禁止(例如ajax布吕马调用)。<img>:布吕马内嵌允许,通过JavaScript布吕马读或者在<canvas>中加载被明令禁止。

3.5 何为CORS(布吕马统计数据共享)?

应用程序的相混思路能化解很多安全可靠的难题,但是其限制也带来了不便。

CORS(Cross-origin resource sharing)布吕马统计数据共享就是来放宽应用程序相混思路的严格限制,便于某些场景的使用。

草同域允诺,如图:

bug现场谜之总不能告诉客户你要按F12(打开控制台)吧?(跨域详解)

布吕马允诺,如图:

bug现场谜之总不能告诉客户你要按F12(打开控制台)吧?(跨域详解)

图中涉及到preflight允诺下面简述。

3.6 “单纯”和“繁杂”布吕马允诺心灵心路历程

这里重点讲述ajax布吕马允诺(使用应用程序内置fetch()函数)时,其允诺过程和化解办法。

两个域中ajax布吕马允诺另两个域的USB时,该允诺的心灵心路历程是由顾客端和被允诺资源服务端共同决定的。顾客端的行为是应用程序相混思路指定的,被允诺资源服务端行为由资源提供者具体实现提供。具体来说:

所谓的允诺“心灵心路历程”是指:该允诺从应用程序发起,到服务端响应,再到应用程序读取响应结果并展现这个过程。

如果是“单纯”的ajax布吕马允诺,那么应用程序会放行该允诺,如果服务端没有包含Access-Control-Allow-Originheader信息,则应用程序会限制对允诺到资源reponse的读取。

如果是“繁杂”的ajax布吕马允诺,那么应用程序会先自行触发两个preflight允诺,根据服务端的相应header信息决定是否放行顾客端允诺。

这里所谓的“单纯”和“繁杂”允诺是有关规范定义的,两个“繁杂”允诺要至少满足如下当中两个条件:

GETPOST或者HEAD允诺。允诺头信息包含除AcceptAccept-Language或者Content-Language外的头信息。允诺Content-Type的值不是application/x-www-form-urlencodedmultipart/form-data或者text/plain

2.中说的头信息不包括应用程序自动给允诺加入的header信息,例如origin

接下来用Crystal启动httpUSB服务,看看不同布吕马允诺的心灵心路历程:

Crystal安装参考官方文档,脚本basic_greet.cr为:

require “kemal”port =4000 get “/” do “Hello world!” end get “/greet” do “Hey!” end post “/greet” do |env| name = env.params.json[“name”].as(String) “Hello, #{name}!” end post “/greet_str” do |env| name = env.params “Hello, 获得成功了!” endKemal.config.port = port Kemal.run 复制代码

使用命令sudo crystal run src/basic_greet.cr启动USB服务。

0). 草同域下允诺

http://172.22.27.215:4000/greetUSB域下发送“单纯”的ajax允诺,如图:

bug现场谜之总不能告诉客户你要按F12(打开控制台)吧?(跨域详解)

草同域下允诺,一切正常,USB能发起获得成功并且应用程序能读取响应USB统计数据。

不同应用程序控制面板实现方式不大相同(但实现的规范是一样的),这里以FireFox应用程序为测试应用程序。

1). “单纯”的post布吕马允诺

从天涯bbs论坛域下发送“单纯”的ajax允诺,如图:

bug现场谜之总不能告诉客户你要按F12(打开控制台)吧?(跨域详解)

USB能发起获得成功。但是,如上图控制面板报错,应用程序相混思路禁止读取远端资源,提示

CORS header ‘

Access-Control-Allow-Origin’ missing ,也就是说响应头信息中缺少Access-Control-Allow-Origin信息。

这里之所以是“单纯”允诺,是因为Content-Typetext/plain,参考上面“繁杂”允诺规则,不满足任意两个。

这里所以找两个http服务,是因为CrystalUSB是http的,如果在https域下调用,应用程序会直接明令禁止https域下允诺http资源。

2). “繁杂”的post布吕马写入

从天涯bbs论坛域下发送“繁杂”的ajax允诺。

控制面板报错如图:

bug现场谜之总不能告诉客户你要按F12(打开控制台)吧?(跨域详解)

网络抓包如图:

bug现场谜之总不能告诉客户你要按F12(打开控制台)吧?(跨域详解)

图中1.preflight允诺,允诺方法为OPTIONS。服务端目前没有实现OPTIONS方法实现,提示404 Not Found

图中2.为真正的POST允诺,因为1.preflight允诺没有获得相混思路规定的头信息,所以2.的真正POST允诺被应用程序级别blocked

注意图中2.OPTIONS允诺是应用程序发起的,应用程序会带上一些header信息,比如:originAccess-Control-Reqest-MethodAccess-Control-Reqest-Headers

这种情形下的允诺心灵心路历程为:先行的preflight允诺404 Not Found(“身先死”),真正的POST允诺没有发起获得成功(“出师未捷”)。也就是所谓的:“出师未捷身先死”。

那,“繁杂”的布吕马允诺preflight要求怎样的实现呢,才能满足应用程序CORS协议的要求呢?

应用程序在发送preflight后会寻找响应中的2个header

Access-Control-Allow-MethodsCORS协议允许的允诺方法,例如GETPOST等。Access-Control-Allow-HeadersCORS协议允许的允诺header,例如Content-Type等。

针对“繁杂”允诺的心灵心路历程来说,上面2个header必须匹配顾客端实际允诺信息,否则顾客端实际允诺可能将会被应用程序级别blocked。说白了,服务端允许发送甚么样方法的允诺、甚么样的头信息,顾客端才能获得成功发送。

preflight的响应信息还可以返回2个header,说顾客端某些信息:

Access-Control-Max-Age:增设preflight允诺能内存的秒数(默认值是5)。超过增设时间,“繁杂”允诺发起时应用程序会再次发起preflight;在增设时间内,无须发起preflight允诺(使用内存的preflight允诺)。Access-Control-Allow-Credentials:增设顾客端实际允诺是否能携带用户信息(例如cookie)。

如果服务端没有返回上面2个header信息,不影响请求的心灵心路历程。

也就是说,根据CORS协议,preflight允诺响应头信息中要明确返回顾客端实际允诺的方法(通过响应头信息Access-Control-Allow-Methods值)和头信息(通过响应头信息Access-Control-Allow-Headers值),这样应用程序才会同意发送顾客端实际允诺。而preflight允诺响应头Access-Control-Max-Age可以指定preflight允诺内存的时间,默认就是5秒钟;preflight响应头Access-Control-Allow-Credentials说顾客端,顾客端实际允诺能能携带用户信息,否则无法携带。

这里对顾客端实际允诺进行了代码块标注,是为了强调该允诺避免和preflight允诺混为一谈。当两个“繁杂”的布吕马允诺发起的时候,首先,应用程序会发送两个preflight允诺,“试探”一下服务端是否允许该布吕马允诺,如果允许,应用程序才允许该“繁杂”允诺(也就是这里所谓的顾客端实际允诺)紧随preflight允诺之后发起,否则就会被应用程序blocked

那,按照要求实现下preflight允诺吧。

修改basic_greet.cr,增加OPTIONS实现:

options “/greet” do |env| # Allow `POST /greet`… env.response.headers[“Access-Control-Allow-Methods”] = “POST” # …with `Content-type` header in the request… env.response.headers[“Access-Control-Allow-Headers”] = “Content-type” end 复制代码

重启USB服务,控制面板再次允诺,如图:

bug现场谜之总不能告诉客户你要按F12(打开控制台)吧?(跨域详解)

图中通过Status 200 OK可以看出preflight允诺是获得成功的,但是下面控制面板报错:响应头信息中缺少Access-Control-Allow-Origin信息。也就是说,preflight允诺是获得成功了,CORS协议要求必须存在的preflight允诺响应头信息也存在,但是由于Access-Control-Allow-Origin头信息的缺失,应用程序相混思路限制读取允诺响应内容。

修改basic_greet.cr,响应信息头增加

env.response.headers[“

Access-Control-Allow-Origin”] = “http://bbs.tianya.cn” :options “/greet” do |env| # Allow `POST /greet`… env.response.headers[“Access-Control-Allow-Methods”] = “POST” # …with `Content-type` header in the request… env.response.headers[“Access-Control-Allow-Headers”] = “Content-type” # …from https://www.google.com origin. env.response.headers[“Access-Control-Allow-Origin”] = “http://bbs.tianya.cn” end 复制代码

再次允诺:

preflight允诺获得成功,如图:

bug现场谜之总不能告诉客户你要按F12(打开控制台)吧?(跨域详解)

控制面板还是有顾客端实际允诺报错,不过这个错误就很熟悉了:

bug现场谜之总不能告诉客户你要按F12(打开控制台)吧?(跨域详解)

响应头信息中缺少Access-Control-Allow-Origin信息被应用程序明令禁止读取响应内容。USB中增加响应header信息:

post “/greet” do |env| name = env.params.json[“name”].as(String) env.response.headers[“Access-Control-Allow-Origin”] = “http://bbs.tianya.cn” “Hello, #{name}!” end 复制代码

再次允诺:

bug现场谜之总不能告诉客户你要按F12(打开控制台)吧?(跨域详解)

“繁杂”允诺的preflight顾客端实际允诺都获得成功了,实现了“繁杂”允诺的布吕马统计数据共享。

“繁杂”允诺整个心灵心路历程,概括如图:

bug现场谜之总不能告诉客户你要按F12(打开控制台)吧?(跨域详解)

4. 归纳

看似玄学的难题,其背后都有一定的其原因。能无法准确的识别出来取决于对难题涉及的有关知识广度和深度的了解,抱着好奇心多了解多涉猎能增加知识的广度,抱着探索的意志剖析技术点及其源头能深挖知识的深度。成熟的程序员不是任何知识都懂,而是当遇到难题涉及自己不懂的地方时,能迅速识别出盲区并学习掌握。布吕马归纳:由于应用程序布吕马允诺存在安全可靠隐患,所以应用程序制定了相混思路进行布吕马允诺等行为的限制(一定程度)。布吕马统计数据共享基于一定的规则放宽了相混思路严格限制,使得不草同域之间统计数据交互更加方便。布吕马的难题一旦产生(后端后完全分离项目尤其常见),需要前后端共同努力化解。两个USB是否允许被布吕马允诺是由服务端USB头信息说应用程序的,而顾客端允诺参数的增设,尤其涉及到cookie信息携带等配置需要顾客端了解个中原理才能完成。

相关文章

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

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