JS系列(一) - 深入浏览器的渲染原理

一. 网页的整体解析流程

1.1. 网页被下载的过程

大家有没有深入思考过:一个网页URL从输入到浏览器中,到显示经历过怎么样的解析过程呢?

网页从服务器下载的过程

整个过程我先做一个简单的概括:

  1. 下载 HTML 文件 当用户在浏览器中输入网址时,浏览器会向服务器发送请求,请求下载网站的 HTML 文件。

  2. 解析 HTML 文件 下载完成后,浏览器开始解析 HTML 文件,并构建 DOM 树。在解析过程中,如果遇到外部链接的 CSS 或 JavaScript 文件,浏览器会发起新的请求来下载这些文件。

  3. 下载 CSS 文件 当浏览器遇到 link 元素时,会发起新的请求来下载该元素的 href 属性指向的 CSS 文件。下载完成后,浏览器会将 CSS 文件解析成 CSSOM 树,并将其与 DOM 树合并,构建出渲染树。

  4. 下载 JavaScript 文件 当浏览器遇到 script 元素时,会发起新的请求来下载该元素的 src 属性指向的 JavaScript 文件。下载完成后,浏览器会解析 JavaScript 代码,并执行其中的命令。在执行过程中,如果代码需要操作 DOM 或 CSSOM 树,浏览器会进行相应的操作。

要想深入理解下载的过程,我们还要先理解,一个index.html被下载下来后是如何被解析和显示在浏览器上的。

注意:关于JavaScript引擎的解析JS代码的过程,我们会在下一篇文章中详细分析。

1.2. 浏览器内核的理解

浏览器解析网页的过程通常是由浏览器内核完成的。

  • 浏览器内核是指浏览器中负责解析 HTML、CSS、JavaScript 等文件的核心组件,也被称为渲染引擎。

当用户在浏览器中输入网址时,浏览器内核会根据协议类型(如 HTTP 或 HTTPS)向服务器发送请求,下载网站的 HTML 文件。

  • 在下载完成后,浏览器内核会开始解析 HTML 文件,构建 DOM 树,根据 DOM 树和 CSS 样式表构建渲染树,最终将页面呈现给用户。

那么常见的浏览器内核有哪些呢?

  1. Trident (三叉戟) Trident 内核最初是由 Microsoft 开发的,用于 Internet Explorer 浏览器。

           后来,一些国内的浏览器厂商(如 360安全浏览器、搜狗高速浏览器、百度浏览器、UC浏览器)也采用了 Trident 内核。

  1. Gecko (壁虎) Gecko 内核最初是由 Mozilla 开发的,用于 Firefox 浏览器。

        Gecko 内核的优势在于支持 HTML5、CSS3 等最新的 Web 标准,并且具有较高的性能和稳定性。

  1. Presto(急板乐曲)-> Blink (眨眼) Presto 内核最初是由 Opera 开发的,用于 Opera 浏览器。

    • 后来,Opera 采用了 Blink 内核,Blink 内核基于 WebKit 内核进行了改进和优化,能够更快地渲染页面,并且支持更多的 HTML5、CSS3 特性。

  2. Webkit WebKit 内核最初是由 Apple 开发的,用于 Safari 浏览器。

    • 现在,很多国内的浏览器厂商(如 360极速浏览器、搜狗高速浏览器)也采用了 WebKit 内核。

    • 除了桌面浏览器,WebKit 内核在移动设备上也得到了广泛的应用,如 iOS 和 Android 系统的浏览器。

  3. Webkit -> Blink Blink 内核最初也是由 Google 开发的,用于 Chrome 浏览器。

    • Blink 内核基于 WebKit 内核进行了改进和优化,并且具有更高的性能和更好的兼容性。

    • 现在,Microsoft Edge 也采用了 Blink 内核。

常见的浏览器内核

我们经常说的浏览器内核指的是浏览器的排版引擎:排版引擎(layout engine),也称为浏览器引擎(browser engine)页面渲染引擎(rendering engine)样版引擎

也就是一个网页下载下来后,就是由我们的渲染引擎来帮助我们解析的。

1.3. 页面渲染整体流程

渲染引擎在拿到一个页面后,如何解析整个页面并且最终呈现出我们的网页呢?

整体的流程图

详细的流程图

上面是渲染引擎的整个工作过程,第一次接触我会觉得有点复杂,我们可以先简单了解它的过程,接下来对其进行详细的解析:

  1. 解析 HTML 文件,构建 DOM 树。

  2. 解析 CSS 文件,构建 CSSOM 树。

  3. 将 DOM 树和 CSSOM 树合并成渲染树。

  4. 生成布局树,计算每个元素在页面上的位置和大小。

  5. 绘制渲染树,将渲染树上的元素绘制成屏幕上的像素。

  6. 合成层,将多个图层合并成一个图层,以便使用 GPU 进行加速。

  7. 使用 GPU 加速,对图层进行合成,形成最终的图像。

  8. 如果发生重绘或回流操作,重新执行步骤 4-7。

有些操作会触发重绘或回流,如改变元素的位置、大小、颜色等。这些操作会影响页面的性能和渲染速度,因此需要尽可能避免。(后续会详细讲解)

二. 页面的详细解析流程

2.1. HTML的解析过程

HTML 解析过程,构建 DOM 树,是浏览器渲染页面的第一步。

  • 因为默认情况下服务器会给浏览器返回index.html文件,所以解析HTML是所有步骤的开始:

HTML的解析效果

HTML 解析过程通常包括以下几个步骤:

  1. 获取 HTML 文件 当用户在浏览器中输入网址时,浏览器会向服务器发送请求,请求下载网站的 HTML 文件。

  2. HTML 标记识别 浏览器会将 HTML 文件解析成一个个标记(tag),如 div、p、img 等等。解析的过程中,浏览器会忽略一些不合法的标记,如没有闭合标签、属性值没有使用引号等等。

  3. DOM 树构建 浏览器会将解析后的标记转化成一个个 DOM 节点(Node),构建成一棵 DOM 树(Document Object Model)。DOM 树是一个树形结构,根节点是 document,其他节点代表 HTML 文档中的元素、属性、文本等等。

在构建 DOM 树的过程中,浏览器会按照 HTML 文档的层次结构,将文档分成一个个的块(block),如文本块、段落块、表格块等等。每个块都会被转换成一个 DOM 节点,节点之间的关系由 HTML 标记之间的关系来确定。

2.2. 解析生成CSS规则

生成 CSS 规则,是浏览器解析 HTML 文件的一部分。

  • 在解析 HTML 文件的过程中,如果遇到 CSS 的 link 元素,浏览器会下载对应的 CSS 文件。

  • 需要注意的是,下载 CSS 文件不会影响 DOM 的解析。

下载完成后,浏览器会对 CSS 文件进行解析,解析出对应的规则树。

  • 这个树形结构称为 CSSOM(CSS Object Model,CSS 对象模型),它描述了 HTML 文档中各元素的样式和布局信息。

在 CSSOM 中,每个节点代表一个 CSS 规则,包括选择器和声明。

  • 选择器指定了哪些元素会被应用这个规则,声明则指定了这些元素的样式属性和值。

  • CSSOM 树的构建过程类似于 DOM 树的构建过程,也是一个逐步解析的过程。

解析生成CSS规则

2.3. 构建RenderTree

当有了DOM Tree和 CSSOM Tree后,就可以两个结合来构建Render Tree了。

构建渲染树的过程

注意事项:

  • 注意一:

    • 需要注意的是,link 元素不会阻塞 DOM 树的构建过程,但会阻塞 Render Tree 的构建过程。

    • 这是因为 Render Tree 在构建时,需要对应的 CSSOM Tree。

  • 注意二:

    • 同时,需要注意的是 Render Tree 和 DOM Tree 并不是一一对应的关系。

    • 例如,对于 display 为 none 的元素,它不会在 Render Tree 中出现。这是因为该元素被隐藏了,不会影响页面的呈现,因此也不需要在渲染树中进行渲染。

2.4. 布局和绘制的过程

 composite 合成的

布局和绘制

步骤4布局的过程:

  • 在步骤 4 中,浏览器会在渲染树(Render Tree)上运行布局(Layout)以计算每个节点的几何体。

  • 渲染树表示显示哪些节点以及其他样式,但不表示每个节点的尺寸、位置等信息。布局是确定呈现树中所有节点的宽度、高度和位置信息。

步骤4绘制的过程:

  • 在步骤 5 中,浏览器将每个节点绘制(Paint)到屏幕上。

  • 在绘制阶段,浏览器将布局阶段计算的每个 frame 转换为屏幕上实际的像素点。

  • 这个过程包括将元素的可见部分进行绘制,例如文本、颜色、边框、阴影、替换元素(例如 img)等等。

2.5. 回流和重绘的问题

这里还有两个比较重要的概念,也是会对浏览器渲染过程中引发性能问题的两个重要概念:回流和重绘。

2.5.1. 回流的解析

理解回流reflow:(也可以称之为重排)

  • 第一次确定节点的大小和位置,称之为布局(layout)。

  • 之后对节点的大小、位置修改重新计算称之为回流。

也就是说回流是指浏览器必须重新计算渲染树中部分或全部元素的几何信息(位置和大小),然后重新构建渲染树的过程。

触发回流的情况有很多,常见的包括:

  1. DOM 结构的变化,比如添加、删除、移动元素等操作;

  2. 改变元素的布局,比如修改元素的宽高、padding、margin、border、position、display 等属性;

  3. 页面的尺寸变化,比如浏览器窗口大小的变化,或者文档视口的变化;

  4. 获取元素的几何属性,比如调用 getComputedStyle() 方法获取元素的尺寸、位置等信息。

回流的代价比较高,因为它会涉及到大量的计算和页面重排,这会导致页面的性能和响应速度下降。

2.5.2. 重绘的解析

理解重绘repaint:

  • 第一次渲染内容称之为绘制(paint)。

  • 之后重新渲染称之为重绘。

重绘是指浏览器不需要重新计算元素的几何信息,而只需要重新绘制元素的内容的过程。

触发重绘的情况有很多,常见的包括:

  1. 修改元素的颜色、背景色、边框颜色、文本样式等属性;

  2. 修改元素的 box-shadow、text-shadow、outline 等属性;

  3. 使用 CSS3 transform 和 opacity 等属性;

  4. 添加、移除、修改元素的 class;

  5. 使用 JavaScript 直接修改样式。

重绘的代价比较小,因为它不涉及到元素的位置和大小等计算,只需要重新绘制元素的内容即可。

回流一定会引起重绘,所以回流是一件很消耗性能的事情。

2.5.3. 页面性能优化

避免回流是提高页面性能的重要手段之一,以下是一些常用的优化方法:

  1. 尽量一次性修改样式 可以使用 cssText 属性、添加 class 等方式,一次性修改元素的样式,避免多次修改引起页面的回流。比如,可以将需要修改的样式保存在一个对象中,然后一次性设置给元素,避免多次触发回流。

  2. 避免频繁的操作 DOM 可以使用 DocumentFragment 或者父元素来操作 DOM,避免频繁地操作 DOM 元素,从而减少页面的回流次数。

  3. 避免使用 getComputedStyle() 获取元素信息 因为 getComputedStyle() 方法会强制浏览器进行回流操作,从而影响页面的性能。如果需要获取元素的信息,可以在修改样式之前先保存到变量中,避免多次触发回流。

  4. 使用 position:absolute 或者 position:fixed 属性 使用 position:absolute 或者 position:fixed 属性可以将元素从文档流中脱离出来,从而避免影响其他元素的位置和大小。虽然这也会引起回流,但是相对于修改文档流中的元素来说,开销较小,对页面的性能影响较小。

总之,避免回流是一项重要的优化技巧,可以帮助我们提高页面的性能和响应速度。可以采用一些常用的优化方法,减少回流的次数,从而提高页面的渲染速度和性能。

2.6. composite合成

绘制的过程,可以将布局后的元素绘制到多个合成图层中。

  • 这是浏览器的一种优化手段;

默认情况下,标准流中的内容都是被绘制在同一个图层(Layer)中的;

而一些特殊的属性,会创建一个新的合成层( CompositingLayer ),并且新的图层可以利用GPU来加速绘制;

  • 因为每个合成层都是单独渲染的;

 

合成层的效果

有些属性可以触发合成层的创建,包括:

  1. 3D 变换(3D Transforms):如 rotateX、rotateY、translateZ 等属性,可以创建一个新的合成层。

  2. video、canvas、iframe 等标签:这些标签会创建一个新的合成层。

  3. opacity 动画转换时:当元素透明度发生变化时,会创建一个新的合成层。

  4. position: fixed:将元素定位为固定位置时,也会创建一个新的合成层。

  5. will-change 属性:可以通过这个实验性的属性,告诉浏览器元素可能会发生哪些变化,从而预先创建合成层。

  6. 动画(Animation)或过渡(Transition)设置了 opacity、transform 属性时,也会创建一个新的合成层。

需要注意的是,过度使用合成层也会带来一些问题,如占用更多的内存、增加页面的复杂度等。

  • 因此,在使用合成层时需要谨慎,避免滥用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
浏览器是重要的互联网入口,一旦受到漏洞攻击,将直接影响到用户的信息安全。作为攻击者有哪些攻击思路,作为用户有哪些应对手段?在本书中我们将给出解答,带你了解浏览器安全的方方面面。本书兼顾攻击者、研究者和使用者三个场景,对大部分攻击都提供了分析思路和防御方案。本书从攻击者常用技巧的“表象”深入介绍浏览器的具体实现方式,让你在知其然的情况下也知其所以然。 第1篇 初探浏览器安全 1 1 漏洞与浏览器安全 3 1.1 漏洞的三要素 3 1.2 漏洞的生命周期 4 1.3 浏览器安全概述 5 1.4 浏览器安全的现状 7 1.5 浏览器的应对策略 9 1.6 “白帽子”与浏览器厂商的联手协作 9 1.7 全书概览 10 1.8 本章小结 12 2 浏览器中常见的安全概念 13 2.1 URL 13 2.1.1 URL的标准形式 15 2.1.2 IRI 16 2.1.3 URL的“可视化”问题——字形欺骗钓鱼攻击 18 2.1.4 国际化域名字形欺骗攻击 19 2.1.5 自纠错与Unicode字符分解映射 20 2.1.6 登录信息钓鱼攻击 23 2.2 HTTP协议 24 2.2.1 HTTP HEADER 25 2.2.2 发起HTTP请求 26 2.2.3 Cookie 28 2.2.4 收到响应 29 2.2.5 HTTP协议自身的安全问题 31 2.2.6 注入响应头:CRLF攻击 31 2.2.7 攻击响应:HTTP 401 钓鱼 32 2.3 浏览器信息安全的保障 33 2.3.1 源 33 2.3.2 同源准则 34 2.3.3 源的特殊处理 34 2.3.4 攻击同源准则:IE11跨任意域脚本注入一例 35 2.4 特殊区域的安全限制 37 2.4.1 安全域 37 2.4.2 本地域 37 2.5 伪协议 38 2.5.1 data伪协议 38 2.5.2 about伪协议 40 2.5.3 javascript/vbscript伪协议 41 2.5.4 伪协议逻辑出错:某浏览器跨任意域脚本注入一例 42 2.6 本章小结 43 3 探索浏览器的导航过程 45 3.1 导航开始 45 3.1.1 浏览器的导航过程 46 3.1.2 DNS请求 46 3.1.3 DNS劫持和DNS污染 47 3.1.4 导航尚未开始时的状态同步问题 48 3.1.5 实例:针对导航过程发起攻击 49 3.2 建立安全连接 50 3.2.1 HTTPS 50 3.2.2 HTTPS请求中的Cookie 51 3.3 响应数据的安全检查——XSS过滤器 52 3.3.1 IE XSS Filter的实现原理 53 3.3.2 Chrome XSSAuditor的工作原理 55 3.4 文档的预处理 56 3.4.1 浏览器对HTML文档的标准化 56 3.4.2 设置兼容模式 57 3.5 处理脚本 59 3.5.1 脚本的编码 60 3.5.2 IE的CSS expression的各种编码模式 62 3.5.3 浏览器的应对策略:CSP 63 3.5.4 “绕过”CSP:MIME Sniff 65 3.5.5 简单的Fuzz:混淆CSS expression表达式 68 3.6 攻击HTML标准化过程绕过IE/Chrome的XSS Filter 71 3.7 本章小结 73 4 页面显示时的安全问题 75 4.1 点击劫持 76 4.1.1 点击劫持页面的构造 76 4.1.2 X-Frame-Options 78 4.2 HTML5的安全问题 80 4.2.1 存储API 81 4.2.2 跨域资源共享 83 4.2.3 基于FullScreen和Notification API的新型钓鱼攻击 84 4.2.4 组合API后可能导致的安全问题 87 4.2.5 引入新的XSS 攻击向量 87 4.2.6 互联网威胁 89 4.3 HTTPS与中间人攻击 92 4.3.1 HTTPS的绿锁 92 4.3.2 HTTPS有多安全? 94 4.3.3 HSTS 96 4.3.4 使用SSLStrip阻止HTTP升级HTTPS 97 4.3.5 使用Fiddler对PC端快速进行中间人攻击测试 99 4.3.6 使用Fiddler脚本和AutoResponse自动发起中间人攻击 101 4.4 本章小结 103 5 浏览器扩展与插件的安全问题 105 5.1 插件 106 5.1.1 ActiveX 106 5.1.2 ActiveX的安全问题 107 5.1.3 ActiveX的逻辑漏洞 108 5.1.4 NPAPI、PPAPI 111 5.2 定制浏览器的扩展和插件的漏洞 113 5.2.1 特权API暴露 114 5.2.2 DOM 修改引入攻击向量 114 5.2.3 Windows文件名相关的多个问题 115 5.2.4 NPAPI DLL的问题 116 5.2.5 同源检查不完善 117 5.2.6 Content Script劫持 118 5.2.7 权限隔离失败 118 5.2.8 配合切核策略+本地内部页XSS执行代码 118 5.2.9 下载服务器限制宽松 119 5.2.10 TLDs判定问题 119 5.2.11 经典漏洞 120 5.2.12 中间人 120 5.3 Adobe Flash插件与Action Script 121 5.3.1 Flash的语言——Action Script 121 5.3.2 Flash文档的反编译、再编译与调试 122 5.3.3 SWF的网络交互:URLLoader 124 5.3.4 crossdomain.xml与Flash的“沙盒” 125 5.3.5 ExternalInterface 126 5.3.6 FLASH XSS 126 5.3.7 Microsoft Edge中的Flash ActiveX 130 5.4 浏览器的沙盒 131 5.4.1 受限令牌 132 5.4.2 完整性级别与IE的保护模式 133 5.4.3 任务对象 134 5.5 本章小结 135 6 移动端的浏览器安全 137 6.1 移动浏览器的安全状况 138 6.2 移动端的威胁 141 6.2.1 通用跨站脚本攻击 141 6.2.2 地址栏伪造 142 6.2.3 界面伪装 143 6.3 结合系统特性进行攻击 144 6.3.1 Android一例漏洞:使用Intent URL Scheme绕过Chrome SOP 144 6.3.2 iOS的一例漏洞:自动拨号泄露隐私 146 6.3.3 Windows Phone一例未修补漏洞:利用Cortana显示IE中已保存密码 147 6.4 本章小结 149 第2篇 实战网马与代码调试 151 7 实战浏览器恶意网页分析 153 7.1 恶意网站中“看得见的”攻防 153 7.2 恶意脚本的抓取和分析 155 7.2.1 发现含攻击代码的网址 156 7.2.2 使用rDNS扩大搜索结果 156 7.2.3 下载攻击代码 157 7.2.4 搭建测试环境 158 7.2.5 初识网马反混淆工具 158 7.2.6 恶意脚本中常见的编码方式 159 7.3 一个简单的挂马代码的处理 169 7.3.1 快速判断挂马 169 7.3.2 JS代码的格式化 170 7.4 更为复杂的代码处理:对Angler网马工具包的反混淆 170 7.4.1 Angler EK的特征 170 7.4.2 推理:找出代码中的“解密-执行”模式 172 7.4.3 检证:确定“解密-执行”模式的位置和方法 175 7.4.4 追踪:使用浏览器特性判断用户环境 179 7.4.5 利用漏洞CVE-2014-6332发起攻击 188 7.5 本章小结 190 8 调试工具与Shellcode 191 8.1 调试工具的用法 191 8.1.1 调试符号 191 8.1.2 WinDbg的用法 192 8.1.3 IDA的用法 195 8.1.4 OllyDbg的用法 199 8.2 与Shellcode的相关名词 201 8.2.1 机器指令 201 8.2.2 控制关键内存地址 203 8.2.3 NOP Slide 204 8.2.4 Magic Number 0x8123 205 8.3 Shellcode的处理 205 8.3.1 实现通用的Shellcode 206 8.3.2 调试网马中的Shellcode 212 8.4 本章小结 218 第3篇 深度探索浏览器漏洞 219 9 漏洞的挖掘 221 9.1 挖0day 221 9.1.1 ActiveX Fuzzer 的原理 221 9.1.2 使用AxMan Fuzzer来Fuzz ActiveX插件 222 9.1.3 现场复现 225 9.2 DOM Fuzzer的搭建 229 9.2.1 搭建运行Grinder的环境 230 9.2.2 Fuzzer的结构与修改 231 9.2.3 现场复现 232 9.3 崩溃分析 233 9.3.1 哪些典型崩溃不能称作浏览器漏洞 233 9.3.2 ActiveX崩溃一例 236 9.3.3 IE11崩溃一例 238 9.4 本章小结 244 10 网页的渲染 245 10.1 网页的渲染 245 10.1.1 渲染引擎 245 10.1.2 DOM结构模型 247 10.1.3 IE解析HTML的过程 249 10.1.4 IE的Tokenize 251 10.1.5 Chrome解析HTML的过程 253 10.1.6 Chrome的Tokenize 254 10.2 元素的创建 256 10.2.1 IE中元素的创建过程 256 10.2.2 Chrome中元素的创建过程 257 10.2.3 元素的生成规律 258 10.3 实战:使用WinDbg跟踪元素的生成 260 10.4 实战:使用WinDbg跟踪元素的插入 263 10.5 实战:使用WinDbg跟踪元素的释放 264 10.6 本章小结 266 11 漏洞的分析 267 11.1 分析IE漏洞CVE-2012-4969 267 11.1.1 崩溃分析 268 11.1.2 追根溯源 270 11.2 分析JScript9漏洞CVE-2015-2425 271 11.2.1 跟踪漏洞 275 11.3 Hacking Team的Flash漏洞CVE-2015-5119 分析 276 11.3.1 静态阅读:成因分析 276 11.3.2 Vector的覆盖过程 278 11.4 本章小结 279 12 漏洞的利用 281 12.1 ShellCode的编写 281 12.2 CVE-2012-4969 的利用 284 12.2.1 DEP/ASLR绕过 287 12.3 CVE-2015-5119的Vector 296 12.4 本章小结 301 附录 303 附录A IE(Edge)的URL截断 303 附录B IE的控制台截断 304 附录C 表单中的mailto: 外部协议 305 附录D 危险的regedit: 外部协议 306 附录E IE XSS Filter的漏洞也会帮助执行XSS 307 附录F 更高级的策略保护——CSP Level 2 308 附录G 更快的执行速度——JScript5 to Chakra 309 附录H Chakra的整数存储 310 附录I 安全实践 311 参考资料 315

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值