彻底理解前端安全面试题(3)—— CORS跨域资源共享,解决跨域问题,建议收藏(含源码)

这篇具有很好参考价值的文章主要介绍了彻底理解前端安全面试题(3)—— CORS跨域资源共享,解决跨域问题,建议收藏(含源码)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言 

前端关于网络安全看似高深莫测,其实来来回回就那么点东西,我总结一下就是 3 + 1  = 4,3个用字母描述的【分别是 XSS、CSRF、CORS】 + 一个中间人攻击。当然 CORS 同源策略是为了防止攻击的安全策略,其他的都是网络攻击。除了这 4 个前端相关的面试题,其他的都是一些不常用的小喽啰。

我将会在我的《面试题一网打尽》专栏中先逐一详细介绍,然后再来一篇文章总结,预计一共5篇文章,欢迎大家关注~

本篇文章是前端网络安全相关的第三篇文章,内容就是 CORS 同源策略。

一、准备工作 

1.1 拉取仓库 

本篇文章的基础是需要一个服务端的项目,可以跟着我的这篇文章搭建自己的服务端项目。或者直接克隆我的仓库代码在这个提交上拉一个新分支,本篇文章所有的代码都是在这个提交基础上进行的。

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

在本篇文章之前,我已经写了 xss 攻击和 csrf 攻击的文章,所以在你拉取我的 git 最新代码的时候,已经有很多更新的提交了。不过,无论是从上面我说的那个提交拉取新分支,还是拉取最新的代码都可以,我的仓库的所有的合并都是相互独立的。

不论你先看 XSS 教程还是先看 CSRF 教程,还是这篇关于跨域的文章都可以。

1.2 新增 CORS 文件夹

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

二、同源策略

两个网站协议名、域名、端口号有一个不同就是非同源,就是跨域。跨域问题就是浏览器的同源策略造成的。

同源是指协议名、域名、端口号 必须完全一致!

http 默认端口号是80,https 默认端口号是443

2.1 同源策略的限制

一般来说,同源策略是指对 javascript 脚本的限制,

  1. js 脚本不能跨域访问 cookie、localstorage、indexDB
  2. js 脚本不能跨域操作 dom
  3. 不能跨域发送 ajax 请求

三、CORS 解决跨域问题

3.1 简单请求

简单请求不会发生跨域 cors 预检请求,预检请求 Preflight Request 是用于验证是否允许非简单请求的一种 OPTIONS 请求。预检请求指示为了减少跨域请求的复杂性和延迟,不是说简单请求就一定不会报跨域错误。而是非简单请求跨域的概率大一些,所以要预检。预检请求是 CORS 机制的一部分,用于确保跨域请求的安全性,预检失败,不会发送实际的跨域请求。

3.1.1 简单请求的条件

(1)head、get、post是这三种方法之一【注意,我们常见的post请求不会发送预检请求】或者

(2)没有自定义 http 请求头,除了下面的字段

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type【只允许3个类型】
  • Range

话虽然这样说,但是实际的简单请求头还有很多字段,比如 orign 、host等【如下图也是一个简单请求的头部】这些字段是浏览器自动设置的。下面的 cache-control 也是浏览器自动加的。

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

(3)content-type 仅限于 application/x-www-form-urlencoded、multipart/form-data、text/plain

注意这三个条件是或的关系,如果 get 请求加上了自定义的请求头,那么就不是简单请求了。或者,简单请求的 content-type 设置了其他值也就不是简单请求了。简单请求的跨域请求不会发送预检请求。

mdn 官网都有说呢

多说无益,直接写代码,你会更好理解。我们看看什么样的情况会有预检请求。

3.1.2 搭建 cors 服务

(1)新建 cors/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    cors
</body>
</html>

(2)新建 cors/index.js

const express = require('express');
const path = require('path');
const bodyParser = require('body-parser')
const app = express();

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

app.get('/', function (req, res) {
  res.sendFile(path.join(__dirname, '/index.html'));
});


app.listen(3000);

(3)运行 npm run dev cors

(4)提交代码

3.1.3  设置 get 非简单请求 

我们要创造一个跨域的请求,但是我们只有一个服务,其实也很简单,那就是使用 localhost 去访问 ip 地址,自然就跨域了。

(1)get 简单请求

我们使用 fetch 只写一个简单的 get 请求,,会发现没有请求列表中没有多余的请求

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

(2)get 自定义请求头

我们给请求加上自定义的请求头,就会多出一个预检请求

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

同理,对于head、post 请求如果我们不加自定义响应头,也不会有预检请求

(3)get 设置 content-type

请求头设置了除了 application/x-www-form-urlencoded、multipart/form-data、text/plain 这三个值之外,都会发送预检请求,可以自己测试一下。

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

content-type 有很多取值,可以自己看一下官方文档。

我们需要记住几个比较常见的

  1. application/json 用于指示请求或响应中的实体是 JSON 格式的数据。

  2. application/xml 用于指示请求或响应中的实体是 XML 格式的数据。

  3. text/html 用于指示请求或响应中的实体是 HTML 格式的文本。

  4. text/plain 用于指示请求或响应中的实体是纯文本,没有特定的格式。【简单请求】

  5. multipart/form-data 用于指示请求中包含多个部分,通常用于文件上传。【简单请求】

  6. application/x-www-form-urlencoded 用于指示请求中的数据是 URL 编码的表单数据,通常用于普通表单提交。【简单请求】

  7. application/octet-stream 用于指示请求或响应中的实体是二进制流,可以是任意类型的数据。

  8. image/jpeg, image/png, image/gif, 等: 用于指示请求或响应中的实体是图片文件,具体的媒体类型根据具体的图片格式而定。

这些只是一些常见的 Content-Type 取值,实际上还有许多其他可能的值,取决于你要传输的数据类型。当你发送 HTTP 请求时,通过设置适当的 Content-Type,可以确保服务器能够正确地解析请求体中的数据。同样,在处理 HTTP 响应时,Content-Type 头部指示了响应中实体的类型,帮助客户端正确解析响应的内容

3.1.4 put、delete 非简单请求

 put 或者 delete等 请求,无论有没有自定义的响应头,无论有没有设置 content-type 都会发送预检请求。

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

再次强调一下,简单请求还是非简单请求,我们研究的前提都是对于跨域请求的,对于非跨域的请求,是没有预检这一说的。 

 3.2  CORS 跨域资源共享

现在我们解决这个跨域的错误,对于跨域问题前端的同学其实不用做什么操作的,主要还是服务端的配置。

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

 3.2.1 安装 cors

pnpm i cors

我们使用的 express 实现跨域,可以直接安装 cors 这个包

3.2.2 修改 index.js

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

就这么简单,就不会有跨域问题了。

我们使用 cors 这个 npm 包就不用手动配置 http 的响应头了。

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

 跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

这里面有一个知识点,就是 http 请求响应的状态码是204

204 No Content

对于该请求没有的内容可发送,但头部字段可能有用。用户代理可能会用此时请求头部信息来更新原来资源的头部缓存字段。

3.2.3 提交代码

3.3 自定义响应头

如果我们不使用 cors 这个包,我们就需要自定义响应头,关于跨域的响应头主要有三个,分别是:

  1. Access-Control-Allow-Origin 允许的 origin
  2. Access-Control-Allow-Methods 允许的方法
  3. Access-Control-Allow-Headers 允许的请求头

3.3.1 设置跨域

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

这里面有个关于 express 的知识点,就是 express 自定义跨域响应头的时候要使用中间件【app.use】,如果你直接在请求中设置是不会生效的,因为跨域请求有一个预检请求。

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

3.3.2 提交代码

3.4 携带凭证

3.4.1 前端携带 cookie

在Web开发中,"携带凭证"(Credentials)是指允许在跨域请求中发送和接收带有身份验证信息的请求。身份验证信息通常包括使用Cookie、HTTP认证或客户端证书等方式进行的用户认证。

我们常说的携带凭证其实就是携带 cookie

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

我们在前端需要修改 index.html

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

关于 fetch 的使用,可以看官网

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

只设置前端是不够的,会报错,服务端需要配置另外一个响应头。

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

3.4.2 服务端允许携带 cookie 

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

 这样就可以完美的携带cookie了

3.4.3 提交代码

四、JSONP 实现跨域

JSONP 就是 JSON with padding,是一种跨域通信技术,为了解决脚本跨域的问题

4.1 JSONP原理

利用 script 标签的跨域特性,script 标签是可以跨域的,在页面中插入一个指向跨域资源的 script 标签,以回调函数的形式返回数据。服务器返回的数据被包装在这个回调函数中,使得跨域请求的数据能够被当前页面取到。

重点如下

  1. 利用 script 标签
  2. 在 script 标签 的 src 中加上 callback 参数函数
  3. 前端定义 callback 函数,并把他的名称拼接在 script 标签的 src 上
  4. 服务器获取 src 上的参数函数,并调用这个函数,给函数传递参数,服务端返回就会执行这个函数,注意到了没有?这个理论逻辑和反射型 xss 攻击是一样的,服务端返回 js 代码,浏览器会自动执行。
  5. 后端调用完参数,前端就自动执行了定义的函数
  6. jsonp 只支持方法
  7. 可能会受到 xss 攻击,所以已经被 cors 所取代

注意到没有,这块和我们之前写的 XSS 攻击的原理类似,具体可以看下这篇文章,里面详细讲解了各种类型的 XSS 攻击。

4.2 代码实现

4.2.1 搭建jsonp 服务器

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

4.2.2 修改 index.js

const express = require('express');
const path = require('path')
const app = express();

app.get('/', function (req, res) {
  res.sendFile(path.join(__dirname, '/index.html'));
});
  
app.get('/data', function (req, res) {
    const { query } = req
    // 获取参数上的回调
    const callback = query.callback
    // 服务端返回执行回调函数,并传递参数 { name: 'test' }
    res.send(`${callback}({ name: 'test' })`)
});
    
app.listen(3000);

4.2.3 修改 index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    jsonp

    <script>
    
      function handleData(data) {
        console.log('jsonp 返回的值', data);
        // 跨域请求,服务端,没有配置可以跨域
        fetch('http://10.10.25.120:3000/data')
      }
    </script>
    <!-- 这个脚本地址要设置成跨域的-->
    <script src="http://10.10.25.120:3000/data?callback=handleData" ></script>
  </body>
</html>

4.2.4 运行

npm run dev jsonp

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

jsonp 发起跨域请求的方式已经很少用了,已经被 CORS 所取代了。

4.2.5 提交代码

五、其他的跨域方式

5.1 postMessage

  1. 页面和其打开的新窗口传递数据
  2. 多窗口之间消息传递
  3. 页面与嵌套的 iframe 消息传递
  4. iframe.contentWindow.postMessage + window.addEventListener

具体使用方法,可以参考这篇文章

5.2 服务器代理

  1. 可以自己定义个 express 服务器进行代理,使用 node + express + http-proxy-middleware 等插件
  2. nginx 做反向代理【反向代理是服务端的代理隐藏真实服务器,正式代理是客户端的代理隐藏客户端】
  3. vue 框架 node + vue + webpack + webpack-dev-server在 config 文件中配置 devServers,原理是利用 http-proxy-middleware + express 这个http代理中间件
  4. vite 框架 config 文件中也可以配置 server proxy
  5. websocket 没有浏览器跨域的限制,因为它基于 tcp 协议
  6. EventSource 基于http,所以会跨域,需要服务端设置请求头。

这里面有个概念,正向代理 vs 反向代理

一句话总结,对客户端的代理是正向代理,对服务端的代理是反向代理,【客户是正面的

~~】

正向代理和反向代理的区别-CSDN博客

5.3 express 实现反向代理

我们接下来用 expess 来实现以下反向代理,对服务端的代理。

应用场景:假设后端给了一个服务地址https://a.com,但是后端这个服务没有设置允许跨域,你要自己调试的时候,就可以自己实现一个本地的、非跨域的服务,然后代理后端的地址。你本地的前端访问你本地的服务http://localhost:3000,你本地的服务再把请求转发给后端的地址。

这里面有个知识点,服务端之间进行请求是不存在跨域的,跨域只针对前端和服务端,因为跨域是浏览器的同源策略,需要有浏览器参与,才有跨域问题。

5.3.1 安装 http-proxy-middleware

pnpm i http-proxy-middleware

5.3.2 搭建 proxy 服务

在根目录下新建  proxy 文件夹,并新建 proxy/index.html 文件、proxy/index.js

假设,本地服务 localhost:3000, 本来需要访问 localhost:3001,但是跨域,因为 localhost:3001的服务没有设置允许跨域;所以可以  localhost:3000 访问  localhost:3000的非跨域服务;同时  localhost:3000 服务在服务器端对 3001 端口进行反向代理。

(1)index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    proxy
    <script>
        // 页面地址 localhost:3000
        // 本来需要请求 localhost:3001,但是跨域,
        // 所以请求 localhost:3000/api/info 进行代理
        function init () {
            // 跨域
            fetch('http://localhost:3001/api/info').then((res) => {
                console.log('请求成功', res)
            }).catch(() => {
                console.log('请求失败')
            })
            // 代理
            fetch('/api/info').then((res) => {
                console.log('请求成功', res)
            })
        }
        init()
    </script>
</body>
</html>
(2)index.js
const express = require('express');
const path = require('path')
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();

app.get('/', function (req, res) {
  res.sendFile(path.join(__dirname, '/index.html'));
});
 
// 把针对 /api 的请求,转发给 3001 端口的服务为
app.use('/api', createProxyMiddleware({
    target: 'http://localhost:3001',
    timeout: 3000,
    changeOrigin: true,
}))

app.listen(3000);

// 第二个服务 3001 端口,未配置允许跨域请求
const app1 = express();
app1.get('/api/info', function(req, res){
    res.send('proxy ok')
})
app1.listen(3001)
(3)运行结果
npm run dev proxy

跨域资源共享测试,面试题穿成串一网打尽,前端,安全,跨域,浏览器

总结

关于跨域的问题已经总结完成,本篇文章详细介绍了如何使用并配置CORS、JSONP 的实现、Express 进行反向代理。

我的仓库地址如下,欢迎查看

yangjihong2113/learn-express

内容较多,难免疏漏,如有问题,欢迎指正。

这是一系列的文章,续更新中,欢迎关注。文章来源地址https://www.toymoban.com/news/detail-790418.html

到了这里,关于彻底理解前端安全面试题(3)—— CORS跨域资源共享,解决跨域问题,建议收藏(含源码)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 移动安全面试题—风控

    延迟处罚型风控如何对抗?群控(工作室)有哪些检测方式? 延迟处罚型风控是指在一段时间内收集和分析用户行为数据,然后根据分析结果对可疑行为进行处罚的风控策略。对抗延迟处罚型风控的方法包括: 行为建模: 对正常用户的行为进行建模,使得恶意行为更接近正

    2024年02月09日
    浏览(47)
  • 2023秋招,网络安全面试题

     Hello,各位小伙伴,我作为一名网络安全工程师曾经在秋招中斩获🔟+个offer🌼,并在国内知名互联网公司任职过的职场老油条,希望可以将我的面试的网络安全大厂面试题和好运分享给大家~ 转眼2023年秋招已经到了金银🔟的关键阶段,宝子们简历抓紧准备投递起来呀,冲冲

    2024年02月15日
    浏览(48)
  • 网络安全面试题汇总(附答案)

    作为从业多年的网络安全工程师,我深知在面试过程中面试官所关注的重点及考察的技能点。网络安全作为当前信息技术领域中非常重要的一部分,对于每一个从事网络安全工作的人员来说,不仅需要掌握一定的技术能力,更需要具备全面的综合素质。 在我职业发展的过程中

    2024年02月13日
    浏览(53)
  • 移动安全面试题—调试&反调试

    Android反调试的几种手段 检测 TracerPid:在 /proc/self/status 文件中,TracerPid 字段表示调试进程的 PID。如果该值非零,则意味着当前进程被调试。 对抗方法:使用内核模块或 Xposed 插件拦截对 /proc/self/status 的读取,将 TracerPid 字段设置为 0。 检测调试端口:/proc/self/maps 文件中包含

    2024年01月19日
    浏览(40)
  • 网络安全书籍推荐+网络安全面试题合集

    一、计算机基础 《深入理解计算机系统》 《鸟哥的Linux私房菜》 《TCP/IP详解(卷1:协议)》 《HTTP权威指南》 《Wireshark数据包分析实战》 《Wireshark网络分析的艺术》 《Wireshark网络分析就这么简单》 二、网络渗透 《白帽子讲Web安全》 《Web安全深度剖析》 《SQL注入天书》

    2023年04月25日
    浏览(48)
  • 史上最全网络安全面试题+答案

    1、什么是SQL注入攻击 前端代码未被解析被代入到数据库导致数据库报错 2、什么是XSS攻击 跨站脚本攻击 在网页中嵌入客户端恶意脚本,常用s语言,也会用其他脚本语言 属于客户端攻击,受害者是用户,网站管理员也属于用户,攻击者一般也是靠管理员身份作为跳板 3、什么

    2024年02月13日
    浏览(54)
  • 史上最全网络安全面试题汇总

    最近有不少小伙伴跑来咨询: 想找网络安全工作,应该要怎么进行技术面试准备? 工作不到 2 年,想跳槽看下机会,有没有相关的面试题呢? 为了更好地帮助大家高薪就业,今天就给大家分享一份网络安全工程师面试题,希望它们能够帮助大家在面试中,少走一些弯路、更

    2024年02月07日
    浏览(55)
  • 2023网络安全面试题(附答案)+面经

    随着国家政策的扶持,网络安全行业也越来越为大众所熟知,相应的想要进入到网络安全行业的人也越来越多,为了拿到心仪的Offer之外,除了学好网络安全知识以外,还要应对好企业的面试。 所以在这里我归纳总结了一些网络安全方面的常见面试题,希望能对大家有所帮助

    2023年04月09日
    浏览(53)
  • 500道网络安全面试题集锦(附答案)

    本篇文章内容为网络安全各个方向涉及的面试题,但是无论如何都无法覆盖所有的面试问题,更多的还是希望由点达面,查漏补缺,然后祝各位前程似锦,都能找到自己满意的工作!   攻击者通过在web界面中嵌入恶意脚本(通常为js代码),造成用户在浏览网页时,控制用户

    2024年02月15日
    浏览(56)
  • 网络安全面试题整理——甲方类(含答案解析)

    以下是对目前部分热门的甲方面试/笔试题(偏管理和运营)的总结和思考,希望可以帮助到正在准备甲方面试的你们; 愿我们披荆斩棘,享受前进路上的每一处风景 1. 简述一下目前主流编程语言的相关漏洞 答:这个题的相关思路就是聊一聊目前主流语言的漏洞,你可以从两

    2024年02月08日
    浏览(61)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包