一道面试题牵出12个前端硬核知识点,你知道几个?(上)

简介: 一道面试题牵出12个前端硬核知识点,你知道几个?(上)

一、概述



640.jpg

1.1 Web页面安全


说到Web页面安全你会想到哪些问题呢?


  1. 什么是同源、什么是同源策略、同源策略的表现是什么?
  2. 浏览器出让了同源策略的哪些安全性?
  3. 跨域解决方案有哪些?
  4. JSONP如何实现?
  5. CORS你了解哪些?
  6. 针对Web页面安全有哪些常见的攻击手段(XSS、CSRF)?


1.2 浏览器网络安全


说到浏览器网络安全你会想到哪些问题呢?


  1. 什么是请求报文?
  2. 什么是响应报文?
  3. HTTP缺点
  4. HTTPS基础知识点
  5. HTTPS流程


1.3 浏览器系统安全


说到浏览器系统安全你会想到哪些问题呢?


  1. 安全沙箱


二、Web页面安全



640.jpg


2.1 同源策略


640.jpg


2.1.1 同源


跨域本质其实就是指两个地址不同源,不同源的反面不就是同源,同源指的是:如果两个URL的协议、域名和端口号都相同,则就是两个同源的URL。


// 非同源:协议不同
http://www.baidu.com
https://www.baidu.com
// 同源:协议、域名、端口号都相同
http://www.baidu.com
http://www.baidu.com?query=1

2.1.2 同源策略

同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的加载的脚本如何能与另一个源的资源进行交互。其主要是为了保护用户信息的安全,防止恶意的网站窃取数据,是浏览器在Web页面层面做的安全保护。

2.1.3 同源策略的表现

既然同源策略是浏览器在Web页面层面做的保护,那么该层面哪些位置需要进行保护呢?总结下来主要包含三个层面:DOM层面、数据层面、网络层面。

  1. DOM层面

同源策略限制了来自不同源的JavaScript脚本对当前DOM对象读和写的操作。

  1. 数据层面

同源策略限制了不同源的站点读取当前站点的Cookie、IndexedDB、localStorage等数据。

  1. 网络层面

同源策略限制了通过XMHttpRequest等方式将站点的数据发送给不同源的站点。

2.1.4 浏览器出让了同源策略的哪些安全性?


640.jpg


2.2 跨域分类


同源策略保证了浏览器的安全,但是如果将这三个层面限制的死死的,则会让程序员的开发工作举步维艰,所以浏览器需要在最严格的同源策略限制下做一些让步,这些让步更多了是在安全性与便捷性的权衡。其实跨域的方式就可以认为是浏览器出让了一些安全性或在遵守浏览器同源策略前提下所采取的一种折中手段。


2.2.1 DOM层面和数据层面分类


根据同源策略,如果两个页面不同源,无法互相操作DOM、访问数据,但是两个不同源页面之间进行通信是比较常见的情形,典型的例子就是iframe窗口与父窗口之间的通信。随着历史的车轮,实现DOM层面间通信的方式有多种,如下所示:


  1. 片段标识符


片段标识符其核心原理就是通过监听url中hash的改变来实现数据的传递,想法真的很巧妙。


// 父页面parentHtml.html
<!DOCTYPE html>
<html lang="zh">
    <head>
        <title></title>
    </head>
    <body>
        我是父页面
        <button id='btn'>父传给子</button>
        <iframe src="./childHtml.html" id="childHtmlId"></iframe>
    </body>
    <script>
        window.onhashchange = function() {
            console.log(decodeURIComponent(window.location.hash));
        };
        document.getElementById('btn').addEventListener('click', () => {
            const iframeDom = document.getElementById('childHtmlId');
            iframeDom.src += '#父传给子';
        });
    </script>
</html>
// 子页面childHtml.html
<!DOCTYPE html>
<html lang="zh">
    <head>
        <title></title>
    </head>
    <body>
        我是子页面
        <button id='btn'>子传给父</button>
    </body>
    <script>
        window.onhashchange = function() {
            console.log(decodeURIComponent(window.location.hash));
        };
        document.getElementById('btn').addEventListener('click', () => {
            parent.location.href += '#子传给父';
        });
    </script>
</html>
  1. window.name


浏览器窗口有window.name属性,这个属性的最大特点是,无论是否同源,只要在同一个窗口里,前一个网页设置了这个属性,后一个网页可以读取它。如果需要实现父页面和跨域的子页面之间的通信,需要一个和父页面同源的子页面作为中介,将跨域的子页面中的信息传递过来。(好麻烦呀,强烈不推荐使用,此处就不写对应的代码啦)


  1. document.domain


document.domain是存放文档的服务器的主机名,可通过手动设置将其设置成当前域名或者上级的域名,当具有相同document.domain的页面就相当于处于同域名的服务器上,如果其域名和端口号相同就可以实现跨域访问数据了。


  1. postMessage(强烈推荐)


window.postMessage是HTML5新增的跨文档通信API,该API,允许跨窗口通信,不论这两个窗口是否同源。


// 父页面
<!DOCTYPE html>
<html lang="zh">
    <head>
        <title></title>
    </head>
    <body>
        我是父页面
        <button id='btn'>父传给子</button>
        <iframe src="http://127.0.0.1:5500/024/childHtml.html" id="childHtmlId"></iframe>
    </body>
    <script>
        window.addEventListener('message', function(event) {
            console.log('父页面接收到信息', event.data);
        });
        document.getElementById('btn').addEventListener('click', () => {
            const iframeDom = document.getElementById('childHtmlId');
            iframeDom.contentWindow.postMessage('我是执鸢者1', 'http://127.0.0.1:5500/024/childHtml1.html');
        });
    </script>
</html>
// 子页面
<!DOCTYPE html>
<html lang="zh">
    <head>
        <title></title>
    </head>
    <body>
        我是子页面
        <button id='btn'>子传给父</button>
    </body>
    <script>
        window.addEventListener('message', function(event) {
            console.log('子页面接收到信息', event.data);
        });
        document.getElementById('btn').addEventListener('click', () => {
            parent.postMessage('我是执鸢者2', 'http://127.0.0.1:5500/024/parentHtml1.html');
        });
    </script>
</html>

2.2.2 网络层面

根据同源策略,浏览器默认是不允许XMLHttpRequest对象访问非同一站点的资源的,这会大大制约生产力,所以需要破解这种限制,实现跨域访问资源。目前广泛采用的主要有三种方式(注:该出不给出具体代码,后续会有专门的百题斩进行详细阐述):

2.2.2.1 通过代理实现

同源策略是浏览器为了安全制定的策略,所以服务端不会存在这样的限制,这样我们就可以将请求打到同源的服务器上,然后经由同源服务器代理至最终需要的服务器,从而实现跨域请求的目的。例如可以通过Nginx、Node中间件等。

2.2.2.2 JSONP的方式

JSONP是一种借助script元素实现跨域的技术,它并没有使用XMLHttpRequest对象,其能够实现跨域主要得益于script有两个特点:

(1)src属性能够访问任何URL资源,并不会受到同源策略的限制;

(2)如果访问的资源包含JavaScript代码,其会在下载后自动执行。

下面一起来实现一下JSONP

  1. 全局挂载一个接收数据的函数;
  2. 创建一个script标签,并在其标签的onload和onerror事件上挂载对应处理函数;
  3. 将script标签挂载到页面中,向服务端发起请求;
  4. 服务端接收传递过来的参数,然后将回调函数和数据以调用的形式输出;
  5. 当script元素接收到影响中的脚本代码后,就会自动执行它们。
function createScript(url, charset) {
    const script = document.createElement('script');
    script.setAttribute('type', 'text/javascript');
    charset && script.setAttribute('charset', charset);
    script.setAttribute('src', url);
    script.async = true;
    return script;
}
function jsonp(url, onsuccess, onerror, charset) {
    const hash = Math.random().toString().slice(2);
    window['jsonp' + hash] = function (data) {
        if (onsuccess && typeof(onsuccess) === 'function') {
            onsuccess(data);
        }
    }
    const script = createScript(url + '?callback=jsonp' + hash, charset);
    // 监听加载成功的事件,获取数据,这个位置用了两个事件onload和onreadystatechange是为了兼容IE,因为IE9之前不支持onload事件,只支持onreadystatechange事件
    script.onload = script.onreadystatechange = function() {
        //若不存在readyState事件则证明不是IE浏览器,可以直接执行,若是的话,必须等到状态变为loaded或complete才可以执行
        if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') {
            script.onload = script.onreadystatechange = null;
            // 移除该script的DOM对象
            if (script.parentNode) {
                script.parentNode.removeChild(script);
            }
            // 删除函数或变量
            window['jsonp' + hash] = null;
        }
    };
    script.onerror = function() {
        if (onerror && typeof(onerror) === 'function') {
            onerror();
        }
    }
    // 添加标签,发送请求
    document.getElementsByTagName('head')[0].appendChild(script);
}
2.2.2.3 CORS方式

跨域资源共享(CORS),该机制可以进行跨域访问控制,从而使跨域数据传输得以安全进行。(实现一个跨域请求的方式,其中html访问网址为http://127.0.0.1:8009; 服务器监听端口为:8010) 一、整体流程

CORS的通信流程是浏览器自动完成,不需要用户参与,其核心点是服务器,只要服务器实现了CORS接口就可以实现跨源通信了。虽然是浏览器自动完成,但是浏览器其实还是根据请求时字段的不同分为简单请求和非简单请求的,下面对这两者进行简要介绍。

  1. 简单请求 (1) 定义

只要满足以下两个条件就属于简单请求:

  1. 请求方法是一下三种方法之一:HEAD、GET、POST;
  2. HTTP的头信息不超出以下几种字段:Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type(其值为application/x-www-form-urlencoded、multipart/form-data、text/plain三个中的一个)。

(2)流程


640.png


简单请求的整个流程可以归结为以下步骤:

1) 浏览器直接发出CORS请求,具体来说就是在头信息之中增加一个Origin字段,该字段用来说明请求来自哪个源(协议+域名+端口),服务器根据这个值决定是否同意这次请求;2)当服务器接收到请求后,根据Origin判定指定的源是否在许可的范围内。3)如果不在许可范围内,服务器会返回一个正常的HTTP回应,浏览器发现该回应的头信息没有包含Access-Control-Allow-Origin字段,就知道出错了,从而抛出错误,被XML的onerror回调函数捕获。(注意:由于正常回应,其状态码为200,所以该错误不能通过状态码识别) 4)如果Origin指定的域名在许可范围内,服务器返回的响应中会多出几个头信息字段(Access-Control-Allow-Origin、Access-Control-Allow-Credentials、Access-Control-Expose-Header等)。

(3)关键字段

1) Access-Control-Allow-Origin

必须字段,该值要么是请求的Origin字段值,要么是一个*(表示接受任意域名的请求)。

2)Access-Control-Allow-Credentials

可选字段,其值是一个布尔值,表示是否允许发送Cookie。默认是不发送Cookie值,当设置为true时,表示服务器明确许可,Cookie可以包含在请求中发送给服务器。(注意:发送Cookie时要注意两点:一方面在Ajax请求中需要设置withCredentials属性;另一方面不能将Access-Control-Allow-Origin设置为*,需要指定明确的、与请求网页一致的域名)

3)Access-Control-Expose-Header

可选字段,当CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段(Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma),如果想获取其它字段必须在Access-Control-Expose-Header中指定。

  1. 非简单请求

(1)定义

不是简单请求的就是非简单请求,非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或Delete,或者Content-Type字段的类型是application/json.

(2)流程

640.png


非简单请求相比于简单请求较复杂,在发起正式请求之前会进行一次预检请求,通过预检请求的结果来决定是否进行后续的正式通信。

1)浏览器发起预检请求,该请求的请求方法是options,该请求是用来询问的;2)服务器收到“预检”请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。3)如果浏览器否定了“预检”请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段,这时浏览器就会认定服务器不同意预检请求,触发错误;4)如果浏览器通过了“预检”请求,以后每次浏览器正常的CORS请求就跟简单请求一样,会有一个Origin头信息字段,服务器的回应也会有一个Access-Control-Allow-Origin头信息字段;

(3)关键字段

1)Access-Control-Request-Method

必须字段,用来列出浏览器的CORS请求会用到哪些HTTP方法。

2)Access-Control-Request-Headers

该字段是一个逗号分隔的字符串,用来指定浏览器CORS请求会额外发送的头信息字段。

3)Access-Control-Allow-Methods

必须字段,该值是一个逗号分隔的字符串,用来表明服务器支持的所有跨域请求的方法。

4)Access-Control-Allow-Headers

该值是一个逗号分隔的字符串,表明服务器支持的所有头信息字段。

5)Access-Control-Max-Age

用来请求预检请求的有效期,单位为秒。

  1. 简单实现

(1)html页面内容

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>test CORS</title>
    </head>
    <body>
        CORS
        <script src="https://code.bdstatic.com/npm/axios@0.20.0/dist/axios.min.js"></script>
        <script>
            axios('http://127.0.0.1:8010', {
                method: 'get'
            }).then(console.log)
        </script>
    </body>
</html>

(2)服务器端代码

const express = require('express');
const app = express();
app.get('/', (req, res) => {
    console.log('get请求收到了!!!');
    res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:8009');
    res.send('get请求已经被处理');
})
app.listen(8010, () => {
    console.log('8010 is listening')
});


相关实践学习
基于函数计算快速搭建Hexo博客系统
本场景介绍如何使用阿里云函数计算服务命令行工具快速搭建一个Hexo博客。
相关文章
|
2天前
|
SQL 分布式计算 监控
Sqoop数据迁移工具使用与优化技巧:面试经验与必备知识点解析
【4月更文挑战第9天】本文深入解析Sqoop的使用、优化及面试策略。内容涵盖Sqoop基础,包括安装配置、命令行操作、与Hadoop生态集成和连接器配置。讨论数据迁移优化技巧,如数据切分、压缩编码、转换过滤及性能监控。此外,还涉及面试中对Sqoop与其他ETL工具的对比、实际项目挑战及未来发展趋势的讨论。通过代码示例展示了从MySQL到HDFS的数据迁移。本文旨在帮助读者在面试中展现Sqoop技术实力。
72 2
|
2天前
|
监控 负载均衡 Cloud Native
ZooKeeper分布式协调服务详解:面试经验与必备知识点解析
【4月更文挑战第9天】本文深入剖析ZooKeeper分布式协调服务原理,涵盖核心概念如Server、Client、ZNode、ACL、Watcher,以及ZAB协议在一致性、会话管理、Leader选举中的作用。讨论ZooKeeper数据模型、操作、会话管理、集群部署与管理、性能调优和监控。同时,文章探讨了ZooKeeper在分布式锁、队列、服务注册与发现等场景的应用,并在面试方面分析了与其它服务的区别、实战挑战及解决方案。附带Java客户端实现分布式锁的代码示例,助力提升面试表现。
129 2
|
2天前
|
XML 分布式计算 监控
Oozie工作流管理系统设计与实践:面试经验与必备知识点解析
【4月更文挑战第9天】本文详述了Oozie工作流管理系统的核心概念,包括安装配置、Workflow XML、Action、Coordinator和Bundle XML定义。此外,讨论了工作流设计实践,如监控调试、自动化运维,并对比了Oozie与其他工作流工具的差异。文中还分享了面试经验及解决实际项目挑战的方法,同时展望了Oozie的未来发展趋势。通过学习,读者能提升Oozie技术能力,为面试做好充分准备。
32 0
|
2天前
|
数据采集 消息中间件 监控
Flume数据采集系统设计与配置实战:面试经验与必备知识点解析
【4月更文挑战第9天】本文深入探讨Apache Flume的数据采集系统设计,涵盖Flume Agent、Source、Channel、Sink的核心概念及其配置实战。通过实例展示了文件日志收集、网络数据接收、命令行实时数据捕获等场景。此外,还讨论了Flume与同类工具的对比、实际项目挑战及解决方案,以及未来发展趋势。提供配置示例帮助理解Flume在数据集成、日志收集中的应用,为面试准备提供扎实的理论与实践支持。
38 1
|
2天前
|
存储 分布式计算 大数据
HBase分布式数据库关键技术与实战:面试经验与必备知识点解析
【4月更文挑战第9天】本文深入剖析了HBase的核心技术,包括数据模型、分布式架构、访问模式和一致性保证,并探讨了其实战应用,如大规模数据存储、实时数据分析及与Hadoop、Spark集成。同时,分享了面试经验,对比了HBase与其他数据库的差异,提出了应对挑战的解决方案,展望了HBase的未来趋势。通过Java API代码示例,帮助读者巩固理解。全面了解和掌握HBase,能为面试和实际工作中的大数据处理提供坚实基础。
51 3
|
2天前
|
SQL 存储 分布式计算
Hive数据仓库设计与优化策略:面试经验与必备知识点解析
本文深入探讨了Hive数据仓库设计原则(分区、分桶、存储格式选择)与优化策略(SQL优化、内置优化器、统计信息、配置参数调整),并分享了面试经验及常见问题,如Hive与RDBMS的区别、实际项目应用和与其他组件的集成。通过代码样例,帮助读者掌握Hive核心技术,为面试做好充分准备。
|
2天前
|
机器学习/深度学习 SQL 分布式计算
Spark核心原理与应用场景解析:面试经验与必备知识点解析
本文深入探讨Spark核心原理(RDD、DAG、内存计算、容错机制)和生态系统(Spark SQL、MLlib、Streaming),并分析其在大规模数据处理、机器学习及实时流处理中的应用。通过代码示例展示DataFrame操作,帮助读者准备面试,同时强调结合个人经验、行业趋势和技术发展以展现全面的技术实力。
|
2天前
|
前端开发 JavaScript 网络协议
前端最常见的JS面试题大全
【4月更文挑战第3天】前端最常见的JS面试题大全
54 5
|
2天前
|
消息中间件 监控 大数据
Kafka消息队列架构与应用场景探讨:面试经验与必备知识点解析
【4月更文挑战第9天】本文详尽探讨了Kafka的消息队列架构,包括Broker、Producer、Consumer、Topic和Partition等核心概念,以及消息生产和消费流程。此外,还介绍了Kafka在微服务、实时数据处理、数据管道和数据仓库等场景的应用。针对面试,文章解析了Kafka与传统消息队列的区别、实际项目挑战及解决方案,并展望了Kafka的未来发展趋势。附带Java Producer和Consumer的代码示例,帮助读者巩固技术理解,为面试做好准备。
29 0
|
2天前
|
监控 Java 应用服务中间件
Spring Boot 源码面试知识点
【5月更文挑战第12天】Spring Boot 是一个强大且广泛使用的框架,旨在简化 Spring 应用程序的开发过程。深入了解 Spring Boot 的源码,有助于开发者更好地使用和定制这个框架。以下是一些关键的知识点:
20 6