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

本文涉及的产品
.cn 域名,1个 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')
});


相关文章
|
12天前
|
缓存 前端开发 中间件
[go 面试] 前端请求到后端API的中间件流程解析
[go 面试] 前端请求到后端API的中间件流程解析
|
1月前
|
存储 算法 安全
Java面试题:Java内存模型及相关知识点深度解析,Java虚拟机的内存结构及各部分作用,详解Java的垃圾回收机制,谈谈你对Java内存溢出(OutOfMemoryError)的理解?
Java面试题:Java内存模型及相关知识点深度解析,Java虚拟机的内存结构及各部分作用,详解Java的垃圾回收机制,谈谈你对Java内存溢出(OutOfMemoryError)的理解?
39 0
|
19天前
|
消息中间件 存储 Java
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android 消息处理机制估计都被写烂了,但是依然还是要写一下,因为Android应用程序是通过消息来驱动的,Android某种意义上也可以说成是一个以消息驱动的系统,UI、事件、生命周期都和消息处理机制息息相关,并且消息处理机制在整个Android知识体系中也是尤其重要,在太多的源码分析的文章讲得比较繁琐,很多人对整个消息处理机制依然是懵懵懂懂,这篇文章通过一些问答的模式结合Android主线程(UI线程)的工作原理来讲解,源码注释很全,还有结合流程图,如果你对Android 消息处理机制还不是很理解,我相信只要你静下心来耐心的看,肯定会有不少的收获的。
59 3
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
|
19天前
|
Android开发
Android面试高频知识点(1) 图解 Android 事件分发机制
在Android开发中,事件分发机制是一块Android比较重要的知识体系,了解并熟悉整套的分发机制有助于更好的分析各种点击滑动失效问题,更好去扩展控件的事件功能和开发自定义控件,同时事件分发机制也是Android面试必问考点之一,如果你能把下面的一些事件分发图当场画出来肯定加分不少。废话不多说,总结一句:事件分发机制很重要。
63 9
|
19天前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
View的绘制和事件处理是两个重要的主题,上一篇《图解 Android事件分发机制》已经把事件的分发机制讲得比较详细了,这一篇是针对View的绘制,View的绘制如果你有所了解,基本分为measure、layout、draw 过程,其中比较难理解就是measure过程,所以本篇文章大幅笔地分析measure过程,相对讲得比较详细,文章也比较长,如果你对View的绘制还不是很懂,对measure过程掌握得不是很深刻,那么耐心点,看完这篇文章,相信你会有所收获的。
39 2
|
1月前
|
缓存 前端开发 JavaScript
高级前端常见的面试题?
【7月更文挑战第11天】 **高级前端面试聚焦候选人的技术深度、项目实战、问题解决及技术趋势洞察。涉及React/Vue生命周期、Redux/Vuex状态管理、Webpack优化、HTTP/HTTPS安全、性能提升策略、PWA、GraphQL、WebAssembly、安全性议题及项目管理。通过回答,展现候选人技术广度与应对复杂场景的能力。**
48 1
|
1月前
|
移动开发 前端开发 JavaScript
前端常见的面试题都有那些?
【7月更文挑战第10天】 前端面试涵盖HTML5新特性、CSS盒模型、JS事件传播、Vue的双向绑定、React生命周期、性能优化策略、浏览器解析流程及安全知识等。例如,HTML5新增video/audio元素、CSS选择器优先级计算、闭包功能、async/await处理异步、Vue通过Object.defineProperty实现数据绑定、React组件生命周期的关键阶段、前端优化如CDN和资源压缩,以及浏览器如何构建渲染树。面试还可能涉及XSS/CSRF防护和框架选择考量。准备面试需全面理解基础概念并结合实践经验。
28 0
|
1月前
|
存储 并行计算 安全
Java面试题:Java内存管理、多线程与并发框架的面试题解析与知识点梳理,深入Java内存模型与垃圾回收机制,Java多线程机制与线程安全,Java并发工具包与框架的应用
Java面试题:Java内存管理、多线程与并发框架的面试题解析与知识点梳理,深入Java内存模型与垃圾回收机制,Java多线程机制与线程安全,Java并发工具包与框架的应用
39 0
|
1月前
|
Java
Java面试题:Java内存模型与并发编程知识点,解释Java中“happens-before”的关系,分析Java中的内存一致性效应(Memory Consistency Effects)及其重要性
Java面试题:Java内存模型与并发编程知识点,解释Java中“happens-before”的关系,分析Java中的内存一致性效应(Memory Consistency Effects)及其重要性
18 0