二狗子翻车了,只因上了这个网站……

今天故事的主角还是大家熟识的二狗子。二狗子拿到了一笔项目奖金,在好好犒劳了自己一顿后,决定把剩下的钱在银行存个定期。

他用浏览器访问了 www.bank.com,输入了用户名和密码后,成功登录。

bank.com 返回了 cookie 用来标识二狗子这个用户。

不得不说,浏览器是个认真负责的工具,它会把这个 cookie 记录下来,以后二狗子每次向 bank.com 发起 HTTP 请求,浏览器都会准确无误地把 cookie 加入到 HTTP 请求头部中,一起发送到 bank.com,这样 bank.com 就知道二狗子已经登陆过了,就可以按照二狗子的请求来做事情,比如查看余额、转账取钱。

二狗子存完钱,看着账户余额,心中暗喜。于是,他打开了 www.meinv.com,去看自己喜欢的电影。

但二狗子不知道的是,浏览器把 meinv.com 的 HTML、JavaScript 都下载到本地,开始执行。而其中某个 JavaScript 中,偷偷创建了一个 XMLHttpRequest 对象,然后向 bank.com 发起了 HTTP 请求 。

浏览器严格按照规定,把之前存储的 cookie 也添加到 HTTP 请求中。但是 bank.com 根本不知道这个 HTTP 请求是 meinv.com 的 JavaScript 发出的,还以为是二狗子发出的。bank.com 检查了cookie,发现这是一个登录过的用户,于是兢兢业业地去执行请求命令,二狗子的个人信息就泄露了。(ps. 实际中实施这样一次攻击不会这么简单,银行网站肯定是做了其他很多安全校验的措施,本故事只是用来说明基本原理。)

可怜的二狗子还不知道发生了什么,已经遭受了钱财损失。那我们来帮他复盘一下为什么会发生这种情况。

首先,每当访问 bank.com 的时候,不管是人点击按钮访问链接,还是通过程序的方式,存储在浏览器的 bank.com 的 cookie 都会进行传递。

其次,从 meinv.com 下载的 JavaScript 利用 XMLHttp 访问了 bank.com。

第一点我们是无法阻止的,如果阻止了,cookie 就丧失了它的主要作用。

对于第二点,浏览器必须做出限制,不能让来自 meinv.com 的 JavaScript 去访问 bank.com。这个限制就是同源策略。

同源策略

浏览器提供了 fetch API 或 XMLHttpRequest 等方式,它们可以使我们方便快捷地向后端发起请求,取得资源,展示在前端上。而通过 fetch API 或 XMLHttpRequest 等方式发起的 HTTP 请求,就必须要遵守同源策略 。
那什么是同源策略呢?同源策略(same-origin policy)规定了当浏览器使用 JavaScript 发起 HTTP 请求时,如果是请求域名同源的情況下,请求不会受到限制。但如果是非同源的请求,则会强制遵守 CORS (Cross-Origin Resource Sharing,跨源资源共享) 的规范,否则浏览器就会将请求拦截。

那什么情况下是同源呢?同源策略非常严格,要求两个 URL 必须满足下面三个条件才算同源:

1、协议(http/https)相同;

2、域名(domain)相同;

3、端口(port)相同。

举个例子:下列哪些 URL 地址与 https://www.bank.com/withdraw.html 属于同源?

  • https://www.bank.com/save.html (✅)

  • http://www.bank.com/withdraw.html (❌,协议不同)

  • https://bank.com/login.html (❌,域名不同)

  • https://www.bank.com:8080/withdraw.html (❌,端口不同)

因此,当我们请求不同源的 URL 地址时,就会产生一个跨域 HTTP 请求(cross-origin http request)。

例如想要在 https://www.upyun.com 的页面上显示来自 https://opentalk.upyun.com 的资讯内容,我们使用浏览器提供的 fetch API 来发起一个请求:

try {
  fetch('https://opentalk.upyun.com/data')
} catch (err) {
  console.error(err);
}

这就产生了一个跨域请求,跨域请求则必须遵守 CORS 的规范。

当请求的服务器没有配置允许 CORS 访问或者不允许来源地址的话,请求就会失败,在 Chrome 的开发者工具台上就会看到以下的经典错误:

Access to fetch at 'https://opentalk.upyun.com/data' from origin 'https://www.upyun.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

那在实际应用中,我们该如何正确地设定 CORS 呢?

什么是 CORS

CORS 是针对不同源(域)的请求而制定的规范。浏览器在请求不同域的资源时,被跨域请求的服务端必须明确地告知浏览器其允许何种请求。只有在服务器允许范围内的请求才能够被浏览器放行并请求,否则会被浏览器拦截,访问失败。

在 CORS 规范中,跨域请求主要分为两种:简单请求(simple request)和非简单请求(not-so-simple request)。

简单请求

简单请求必须符合以下四个条件,实际开发中我们一般只关注前面两个条件:

(1)使用 GET、POST、HEAD 其中一种方法;

(2)只使用了如下的安全请求头部,不得人为设置其他请求头部:

  • Accept

  • Accept-Language

  • Content-Language

Content-Type 仅限以下三种:

  • text/plain

  • multipart/form-data

  • application/x-www-form-urlencoded

(3)请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器,XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问;

(4)请求中没有使用 ReadableStream 对象。

不符合以上任一条件的请求就是非简单请求。浏览器对于简单请求和非简单请求,处理的方式也不一样。

对于简单请求,浏览器会直接发出 CORS 请求。具体来说,就是在请求头信息中,自动地增加一个Origin (来源)字段。

Origin 的值中,包含请求协议、域名和端口三个部分,用于说明本次请求来自哪个源。服务器可以根据这个值,决定是否同意这次请求。例如下面的请求头报文:

GET /data HTTP/2
Host: opentalk.upyun.com
accept-encoding: deflate, gzip
accept: */*
origin: https://www.upyun.com
......

如果 Origin 指定的源不在服务器允许范围内,服务器会返回响应一个正常的 HTTP,浏览器发现回应头部中,如果没有包含 Access-Control-Allow-Origin 字段,就会抛出错误。需要注意的是,这种错误无法通过状态码识别,HTTP 响应的状态码有可能是 200。

如果 Origin 指定的源在允许范围内的话,响应头部中,就会有以下几个字段:

Access-Control-Allow-Origin: https://www.upyun.com
Access-Control-Allow-Headers: Authorization
Access-Control-Expose-Headers: X-Date
Access-Control-Allow-Credentials: true

大家可能也看出来了一个特点,与 CORS 请求相关的字段,都以 Access-Control- 开头。

如果跨域请求是被允许的,那么响应头部中是必须有 Access-Control-Allow-Origin 头部的。它的值要么是请求时 Origin 字段的值,要么是一个 *,表示接受任意域名的请求。

Access-Control-Allow-Credentials 是一个可选字段,它的值是一个布尔值,表示是否允许发送Cookie。如果发起跨域请求时,设置了 withCredentials 标志为 true,浏览器在发起跨域请求时,也会同时向服务器发送 cookie。如果服务器端的响应中不存在 Access-Control-Allow-Credentials 头部,浏览器就不会响应内容。

特别需要说明的是,如果请求端设置了 withCredentials ,Access-Control-Allow-Origin 的值就必须是具体的域名值,而不能设置为 *,否则浏览器也会抛出跨域错误。

Access-Control-Expose-Headers 也是一个可选头部。当进行跨域请求时,XMLHttpRequest 对象的 getResponseHeader()方法只能拿到 6 个基本响应字段:

  • Cache-Control

  • Content-Language

  • Content-Type

  • Expires

  • Last-Modified

  • Pragma

而如果开发者需要获取其他响应头部字段,或者一些自定义响应头部,服务器就可以通过设置 Access-Control-Expose-Headers 头部来指定发起端可访问的响应头部。

非简单请求

非简单请求往往是对服务器有特殊要求的请求,比如请求方法为 PUT 或 DELETE,或者 Content-Type 字段类型是 application/json。

对于非简单请求的 CORS 请求,浏览器会在正式发起跨域请求之前,增加一次 HTTP 查询请求,我们称为预检请求(preflight)。浏览器会先询问服务器,当前的域名是否在服务器的许可名单之中,以及可以使用哪些 HTTP 请求方法和请求头部字段。只有得到肯定答复,浏览器才会发出正式的跨域请求,否则就会报错。

比方说我们使用代码发起一个跨域请求:

fetch('http://opentalk.upyun.com/data/', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    'X-CUSTOM-HEADER': '123'
  }
})

浏览器会发现这是一个非简单请求,它会自动发送一个 OPTIONS 的预检请求,其中核心内容有两部分,Access-Control-Request-Method 表示后面的跨域请求需要用到的方法,Access-Control-Request-Headers 表示后面的跨域请求头内会有该内容。

OPTIONS /data/ HTTP/1.1
Host: opentalk.upyun.com
Origin: http://www.upyun.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-MY-CUSTOM-HEADER, Content-Type

服务器收到预检请求后,检查这些特殊的请求方法和头自己能否接受,如果接受,会在响应头部中包含如下信息:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH
Access-Control-Max-Age: 86400
Access-Control-Allow-Headers: X-Date, range, X-Custom-Header, Content-Type
Access-Control-Expose-Headers: X-Date, X-File, Content-type
......

上面的 HTTP 响应中,关键的是 Access-Control-Allow-Origin 字段,* 表示同意任意跨源请求都可以请求数据。部分字段我们在简单请求中解释过了,这里挑几个需要注意的头部解释一下。

  • Access-Control-Allow-Methods,这是个不可缺少的字段,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。

  • Access-Control-Allow-Headers 字段为一个逗号分隔的字符串,表明服务器支持的所有请求头部信息字段,不限于浏览器在预检中请求的字段。

  • Access-Control-Max-Age:该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是 1 天(86400 秒),在此期间,不用再发出另一条预检请求。

相关推荐

3 分钟了解 NVIDIA 新出的 H200

英伟达在 2023 年全球超算大会上发布了备受瞩目的新一代 AI 芯片——H200 Tensor Core GPU。相较于上一代产品 H100,H200 在性能上实现了近一倍的提升,内存容量翻倍,带宽也显著增加……

github_36774378的博客 2380

深入了解浮点运算——CPU 和 GPU 算力是如何计算的

算力最基本的计量单位是 FLOPS,英文 Floating-point Operations Per Second,即每秒执行的浮点运算次数。浮点运算其实就是带小数的加减乘除运算。

github_36774378的博客 5104

加速计算,为何会成为 AI 时代的计算力“新宠”

加速计算是指使用专用硬件来执行某些类型的计算,其效率要比仅使用通用中央处理器(CPU)高。利用图形处理单元(GPU)、专用集成电路(ASIC)(包括张量处理单元(TPU))和现场可编程逻辑门阵列(FPGA)等设备的强大功能,以更高的速度执行计算,从而加速计算过程,一般我们也将这些设备称之为加速器。这些加速器尤其适用于可被分解为较小并行任务的项目,如高性能计算 (HPC)、深度学习、机器学习、人工智能和大数据分析。通过将指定类型的工作分派到这些专用加速计算硬件上,大大提高了系统的性能和效率。

github_36774378的博客 1072

NVIDIA RTX4090,你能用它做什么?

如果女生选择给男生送礼,我相信一块 RTX4090 就足以让他高兴得死去活来。RTX4090 到底是何方神圣?它凭什么赢得所有男生的“芳心”?

github_36774378的博客 2353

3 分钟看完 NVIDIA GPU 架构及演进

近期随着 AI 市场的爆发式增长,作为 AI 背后技术的核心之一 GPU(图形处理器)的价格也水涨船高。GPU 在人工智能中发挥着巨大的重要,特别是在计算和数据处理方面。目前生产 GPU 主流厂商其实并不多,主要就是 NVIDIA、AMD、Intel、高通等厂家。本文将主要聊聊 NVIDIA GPU 的核心架构及架构演进。

github_36774378的博客 1983

聊聊 GPU 产品选型那些事

随着人工智能的飞速崛起,随之而来的是算力需求的指数级增加,CPU 已经不足以满足深度学习、大模型计算等场景的海量数据处理需求。GPU 作为一种强大的计算工具,无论是高性能计算、图形渲染还是机器学习领域,在各个领域展现出了巨大的潜力和应用前景。说起 GPU,绕不过的当然是 NVIDIA 这个公司了,现在市面上火热的 A100/A800、H100 等 GPU 全是他家的产品。但当你有业务需求或者个人需求,想要采购 GPU 的时候,你会发现各个型号的 GPU 令你眼花缭乱。

github_36774378的博客 985

巅峰对决:英伟达 V100、A100/800、H100/800 GPU 对比

近期,不论是国外的 ChatGPT,还是国内诸多的大模型,让 AIGC 的市场一片爆火。而在 AIGC 的种种智能表现背后,均来自于堪称天文数字的算力支持。以 ChatGPT 为例,据微软高管透露,为 ChatGPT 提供算力支持的 AI 超级计算机,是微软在 2019 年投资 10 亿美元建造一台大型顶尖超级计算机,配备了数万个 NVIDIA A100 GPU,还配备了 60 多个数据中心总共部署了几十万个 NVIDIA GPU 辅助。

github_36774378的博客 1万+

InfiniBand 的前世今生

今年,以 ChatGPT 为代表的 AI 大模型强势崛起,而 ChatGPT 所使用的网络,正是 InfiniBand,这也让 InfiniBand 大火了起来。那么,到底什么是 InfiniBand 呢?下面,我们就来带你深入了解 InfiniBand。

github_36774378的博客 865

揭秘神秘的字符串匹配工具——正则表达式

每个正则表达式都有一个有限自动机(也称为状态机),它接受表达式指定的语言,并使用 Thompson 构造算法将正则表达式转化为一个与之等价的非确定有限状态自动机(NFA)。同时,对于每个有限自动机来说,还有一个描述该自动机所接受语言的正则表达式。该表达式可以通过克莱恩算法或高斯消元法生成。正则表达式的一个著名应用是文本编辑器中的搜索和替换功能,计算机先驱 Ken Thompson( UNIX 操作系统的开发者之一)首先在 20 世纪 60 年代的面向行编辑器 QED 中实现了该功能。

github_36774378的博客 382

深入了解 GPU 互联技术——NVLINK

随着人工智能和图形处理需求的不断增长,多 GPU 并行计算已成为一种趋势。对于多 GPU 系统而言,一个关键的挑战是如何实现 GPU 之间的高速数据传输和协同工作。然而,传统的 PCIe 总线由于带宽限制和延迟问题,已无法满足 GPU 之间通信的需求。为了解决这个问题,NVIDIA 于 2018 年推出了 NVLINK,以提高 GPU 之间的通信效率。

github_36774378的博客 3874

各快 100 倍?4G、5G、6G 相差这么多吗

二狗子今天晚上有点 emo,为什么呢?原来是二狗子心心念很久的一个手游上线了,二狗子兴冲冲地下载了 40 多分钟,终于下载完了游戏。结果打开游戏一看,发现游戏内部的更新写着预计 30 分钟完成更新。这就把二狗子搞得 emo 了。二狗子突然发现自己的室友已经在这款游戏的新手村大杀四方了。“你怎么这么快?”二狗子问。“我用手机流量下载的,5G,当然快。”室友都没看二狗子一眼,沉浸在自己的游戏世界里。5G 真的有这么快吗?好学的二狗子就让游戏保持着后台更新,在网上冲浪学习下知识充实自己。

github_36774378的博客 468

为什么大家都在用 WebP?

WebP 是谷歌在 2010 年提出的一种新型的图片格式,放到现在来讲,已经不算是“新”技术了,毕竟已经有了更新的 JPEG XL 和 AVIF。但是在日常工作中,大家时常会碰到保存下来的图片的后缀是 .webp。那么 WebP 到底有什么魔力,让越来越多的网站“抛弃”常用的 PNG、JPG 而青睐它呢?

github_36774378的博客 958

从驾考科目二到自动驾驶,聊聊 GPU 为什么对自动驾驶很重要

这些数据包含前车和本车的距离,左右两边的道路指示标志,周围汽车的距离,前方道路指示标志,红绿灯信号,马路边行人,非机动车等信息等,大量的图像和视频信息被转换成电脑能处理的二进制信息,这就需要 CPU 和 GPU 的共同加持才能完成安全稳定的自动驾驶工作。

github_36774378的博客 361

聊透 GPU 通信技术——GPU Direct、NVLink、RDMA

AI 技术对算力的需求是非常庞大的,虽然 GPU 的计算能力在持续提升,但是对于 AI 来说,单卡的计算能力就算再强,也是有极限的,这就需要多 GPU 组合。而 GPU 多卡的组合,主要分为单个服务器多张 GPU 卡和多个服务器,每个服务器多张卡这两种情况,无论是单机多卡还是多机多卡,GPU 之间需要有超强的通信支持。

github_36774378的博客 2569

这个 AI 机器人会怼人,它是怎么做到的?

人工智能可以定义为计算机科学的一个分支,其目标是创造与人类智力相当的技术。但智力到底是什么?如何利用技术来复制智力?这个疑问并不存在单一的理解,目前已经有了许多理论和方法来回答这些问题。人工智能的实现方式主要有两种:一种是基于规则的人工智能,通过预先编写的规则和逻辑来实现特定的任务;另一种是基于机器学习的人工智能,通过让计算机从数据中学习和优化算法,来实现特定的任务。

github_36774378的博客 717

如何评估计算机的算力:从 CPU 到 GPU 的演变

这就是 CPU 和 GPU 在计算能力上的区别,这是由它们的架构决定的,CPU 可以执行任何程序,而 GPU转为多任务而生,并发能力强。当然,上面的两张图并不是说 GPU 比 CPU 厉害,事实上,CPU 和 GPU 各自具有不同的特点和优势,选择哪种设备取决于具体的应用场景和需求。其中,CPU(中央处理器)和 GPU(图形处理器)是计算机中最为核心的两个组件,它们的算力和性能对于计算机的整体性能具有决定性的影响。CPU 是计算机的核心组件之一,它的主要功能是执行指令、控制计算机的运行和处理数据等任务。

github_36774378的博客 2390

浅谈 Linux 下 vim 的使用

底线模式的进入方法为:在命令模式下按":“键,Vim 窗口的左下方会出现一个”:"符号,这时就可以输入相关的指令进行操作了。在此模式下可以使用上、下、左、右键或者k、j、h、l键进行光标的移动,还可以对文件内容进行复制、粘贴、替换、删除等操作。当编辑完成,就可以按 Esc 退出插入模式,进入到命令模式。p : 黏贴,此命令是在命令模式下,按照上面的命令复制后,然后光标移动到想要复制的位置,然后按 p 黏贴。直接到某行:在底线模式下直接输入数字就可以到想到的行,如果输入的数字比文档的行数多就会到最后一行。

github_36774378的博客 1311

如何高效实现 MySQL 与 elasticsearch 的数据同步

MySQL 自身简单、高效、可靠,是又拍云内部使用最广泛的数据库。但是当数据量达到一定程度的时候,对整个 MySQL 的操作会变得非常迟缓。而公司内部 robin/logs 表的数据量已经达到 800w,后续又有全文检索的需求。这个需求直接在 MySQL 上实施是难以做到的。

github_36774378的博客 724

国密证书 VS 传统 SSL 证书,到底区别在哪?

国密算法,即国家商用密码算法。是我国自主研发创新的一套数据加密处理系列算法。从 SM1-SM4 分别实现了对称、非对称、摘要等算法功能。尤其适用于嵌入式物联网等相关领域,完成身份认证和数据加解密等功能。

github_36774378的博客 1310

又拍云邵海杨 - 25年Linux老兵,聊聊运维的“术”与“道”

邵海杨,从1998年开始使用Linux至今快25年了,资深Linux系统运维/架构师,DevOps八荣八耻倡导者,喜欢交流分享,活跃于社区,一直积极投身于开源活动的组织和传播。

github_36774378的博客 745

从 AI 绘画到 ChatGPT,聊聊生成式 AI

无论是 AI 绘画,还是现在风靡全球的 ChatGPT,它们都属于 AI 的一个分支——生成式AI(Generative AI)。相较于传统的 AI 模型,生成式 AI 是一种特定类型的 AI,它专注于创建新内容。

github_36774378的博客 5755

从 B 站出发,用 Chrome devTools performance 分析页面如何渲染

页面是如何渲染的?从 Chrome 的性能工具开始,具体看看一个页面是如何进行渲染的,以及进行页面优化时需要关注哪些指标。

github_36774378的博客 1136

【白话科普】聊聊网络架构变革的关键——SDN

SDN 即软件定义网络,它描述了一种网络架构,可以使用软件对单个硬件组件进行集中、智能的管理和控制,使用 OpenFlow 等开放协议允许访问网络设备,如交换机、路由器或防火墙等。

github_36774378的博客 1838

一文读懂 Kubernetes 存储设计

在 Docker 的设计中,容器内的文件是临时存放的,通过在 docker run 启动容器时,使用 --volume/-v 参数来指定挂载卷,将容器内部的路径挂载到主机,来保证即便容器被删除,保存到主机路径中的数据也仍然存在。

github_36774378的博客 545

从实战出发,聊聊缓存数据库一致性

在云服务中,缓存是极其重要的一点。所谓缓存,其实是一个高速数据存储层。本文主要介绍更新数据库成功后,更新缓存和删除缓存这两个操作的区别和改进方案。

github_36774378的博客 584

当谈论 React hook,我们究竟说的是什么?

React hook是什么,所谓 React hook,就是增强函数组件能力特性的钩子,把不同的特性「钩」进纯函数。React hook 的由来,其实也可以看作是前端技术不断演进的结果。

github_36774378的博客 589

视频网站节约 30% 成本的秘密在这里

今年,爱奇艺宣布2022年第一季度首次实现季度盈利,长视频行业发展十几年来,一直深陷亏损旋涡。爱奇艺的首次实现季度盈利,也意味着降本增效将成为视频平台的发展方向。

github_36774378的博客 965

【白话科普】从“熊猫烧香”聊聊计算机病毒

到底什么是计算机病毒呢?它是什么途径传播的,又会带来哪些危害,我们又该如何在日常使用电脑中防止感染病毒呢?

github_36774378的博客 1642

【实操日记】使用 PyQt5 设计下载远程服务器日志文件程序

PyQt5 是一套 Python 绑定 Digia Qt5 应用的框架,是最强大的 GUI 库之一,使用 PyQt5 我们能够很容易的开发桌面应用,我们如何用 PyQt5 设计一个下载服务器指定日期日志文件的程序。

github_36774378的博客 1117

又拍云之 Keepalived 高可用部署

Keepalived 是什么,它一款基于 VRRP 协议的高可用软件,借助它可以让多台服务器能像路由器一样做 VIP 虚拟地址的冗余转移,从而提升后端服务器的高可靠性。

github_36774378的博客 1288
上一篇: 一文读懂 Kubernetes 存储设计
下一篇: 【白话科普】聊聊网络架构变革的关键——SDN
又拍云 UPYUN
又拍云 UPYUN 又拍云官方账号 又拍云官方账号
博客等级 码龄10年 153粉丝 174原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值