浏览器渲染原理及流程

2017/05/26 · 基础技术 ·
浏览器

原文出处: 李某龙   

我们可能都知道浏览器含有一个渲染引擎,用来渲染窗口所展示的内容。默认情况下,渲染引擎可以显示html、xml文档及图片,它也可以借助插件(一种浏览器扩展)显示其他类型数据,例如使用PDF阅读器插件,用于显示PDF格式。但是其具体的渲染原理和流程估计也有很多人都不知道或者不清楚吧。这些天研究了一下浏览器的渲染原理,有了些心得,在这里跟大家分享一下,这里只讨论渲染引擎最主要的用途——显示应用了CSS之后的html及图片。

渲染引擎简介

本文所讨论的浏览器——Firefox、Chrome和Safari是基于两种渲染引擎构建的,Firefox使用Geoko——Mozilla自主研发的渲染引擎,Safari和Chrome都使用webkit。

渲染主流程

渲染引擎首先通过网络获得所请求文档的内容,通常以8K分块的方式完成。下面是渲染引擎在取得内容之后的基本流程:

解析html以构建dom树 -> 构建render树 -> 布局render树 ->
绘制render树

图片 1

这里先解释一下几个概念,方便大家理解:

DOM Tree:浏览器将HTML解析成树形的数据结构。

CSS Rule Tree:浏览器将CSS解析成树形的数据结构。  

Render Tree: DOM和CSSOM合并后生成Render Tree。

layout: 有了Render
Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系,从而去计算出每个节点在屏幕中的位置。

painting: 按照算出来的规则,通过显卡,把内容画到屏幕上。

reflow(回流):当浏览器发现某个部分发生了点变化影响了布局,需要倒回去重新渲染,内行称这个回退的过程叫 reflow。reflow
会从这个 root frame
开始递归往下,依次计算所有的结点几何尺寸和位置。reflow 几乎是无法避免的。现在界面上流行的一些效果,比如树状目录的折叠、展开(实质上是元素的显 示与隐藏)等,都将引起浏览器的 reflow。鼠标滑过、点击……只要这些行为引起了页面上某些元素的占位面积、定位方式、边距等属性的变化,都会引起它内部、周围甚至整个页面的重新渲 染。通常我们都无法预估浏览器到底会 reflow 哪一部分的代码,它们都彼此相互影响着。

repaint(重绘):改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性时,屏幕的一部分要重画,但是元素的几何尺寸没有变。

注意:(1)display:none 的节点不会被加入Render Tree,而visibility: hidden
则会,所以,如果某个节点最开始是不显示的,设为display:none是更优的。   

(2)display:none 会触发 reflow,而 visibility:hidden 只会触发
repaint,因为没有发现位置变化。

(3)有些情况下,比如修改了元素的样式,浏览器并不会立刻reflow 或 repaint
一次,而是会把这样的操作积攒一批,然后做一次 reflow,这又叫异步 reflow
或增量异步 reflow。但是在有些情况下,比如resize
窗口,改变了页面默认的字体等。对于这些操作,浏览器会马上进行 reflow。 

来看看webkit的主要流程:

图片 2

再来看看Geoko的主要流程:

图片 3

Gecko 里把格式化好的可视元素称做“帧树”(Frame
tree)。每个元素就是一个帧(frame)。 webkit
则使用”渲染树”这个术语,渲染树由”渲染对象”组成。webkit
里使用”layout”表示元素的布局,Gecko则称为”reflow”。Webkit使用”Attachment”来连接DOM节点与可视化信息以构建渲染树。一个非语义上的小差别是Gecko在HTML与DOM树之间有一个附加的层
,称作”content sink”,是创建DOM对象的工厂。

尽管Webkit与Gecko使用略微不同的术语,这个过程还是基本相同的,如下:

  1. 浏览器会将HTML解析成一个DOM树,DOM
    树的构建过程是一个深度遍历过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。

  2. 将CSS解析成 CSS Rule Tree 。

  3. 根据DOM树和CSSOM来构造 Rendering Tree。注意:Rendering Tree
    渲染树并不等同于 DOM
    树,因为一些像Header或display:none的东西就没必要放在渲染树中了。

  4. 有了Render
    Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系。下一步操作称之为layout,顾名思义就是计算出每个节点在屏幕中的位置。

  5. 再下一步就是绘制,即遍历render树,并使用UI后端层绘制每个节点。

注意:上述这个过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽可能早的将内容呈现到屏幕上,并不会等到所有的html都解析完成之后再去构建和布局render树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容

1 赞 5 收藏
评论

图片 4

详解 JS 变量、作用域及内存

2016/10/19 · JavaScript
· 3 评论 ·
作用域,
内存,
变量

原文出处: trigkit4   

基本类型值有:undefined,NUll,Boolean,Number和String,这些类型分别在内存中占有固定的大小空间,他们的值保存在栈空间,我们通过按值来访问的。

JavaScript

(1)值类型:数值、布尔值、null、undefined。
(2)引用类型:对象、数组、函数。

1
2
(1)值类型:数值、布尔值、null、undefined。
(2)引用类型:对象、数组、函数。

如果赋值的是引用类型的值,则必须在堆内存中为这个值分配空间。由于这种值的大小不固定(对象有很多属性和方法),因此不能把他们保存到栈内存中。但内存地址大小是固定的,因此可以将内存地址保存在栈内存中。

<script type=”text/javascript”> var box = new Object();
//创建一个引用类型 var box = “trigkit4”; //基本类型值是字符串 box.age =
21; //基本类型值添加属性很怪异,因为只有对象才可以添加属性。
alert(box.age); //不是引用类型,无法输出; </script>

1
2
3
4
5
6
<script type="text/javascript”>
var box = new Object();  //创建一个引用类型
var box = "trigkit4";   //基本类型值是字符串
box.age = 21;    //基本类型值添加属性很怪异,因为只有对象才可以添加属性。
alert(box.age);  //不是引用类型,无法输出;
</script>

简而言之,堆内存存放引用值,栈内存存放固定类型值。“引用”是一个指向对象实际位置的指针。

在这里需注意的是,引用指向的是具体的对象,而不是另一个引用。

图片 5

这里的对象可以是字符串对象,数字对象,数组对象等

JavaScript

<script type=”text/javascript”> var man = new
Object();//man指向了栈内存的空间地址 man.name = “Jack”; var man2 =
man;//man2获得了man的指向地址 alert(man2.name);//两个都弹出Jack
alert(man.name); </script>

1
2
3
4
5
6
7
8
<script type="text/javascript">
    var man = new Object();//man指向了栈内存的空间地址
    man.name = "Jack";
    var man2 = man;//man2获得了man的指向地址
 
    alert(man2.name);//两个都弹出Jack
    alert(man.name);
</script>

Web 安全之 XSS

2018/05/25 · JavaScript
· 1 评论 ·
XSS

原文出处:
今日头条技术博客   

复制变量值

再看下面这个例子:

JavaScript

<script type=”text/javascript”> var man = new
Object();//man指向了栈内存的空间地址 man.name = “Jack”; var man2 =
man;//man2获得了man的指向地址 man2.name =
“ming”;//因为他们都指向同一个object,同一个name,不管修改谁,大家都修改了
alert(man2.name);//两个都弹出ming alert(man.name); </script>

1
2
3
4
5
6
7
8
9
<script type="text/javascript">
    var man = new Object();//man指向了栈内存的空间地址
    man.name = "Jack";
    var man2 = man;//man2获得了man的指向地址
 
    man2.name = "ming";//因为他们都指向同一个object,同一个name,不管修改谁,大家都修改了
    alert(man2.name);//两个都弹出ming
    alert(man.name);
</script>

由以上可以得出:在变量复制方面,基本类型和引用类型也有所不同,基本类型复制的是值本身,而引用类型复制的是地址。

什么是XSS

跨站脚本攻击(Cross Site Scripting),为不和层叠样式表(Cascading Style
Sheets,
CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。

传递参数

ECMAScript中,所有函数的参数都是按值传递的,

JavaScript

<script type=”text/javascript”> function box(num){ //按值传递
num+=10; return num; } var num = 10; var result = box(num);
alert(result);
//如果是按引用传递,那么函数里的num会成为类似全局变量,把外面的number替换掉
alert(num); //也就是说,最后应该输出20(这里输出10) </script>

1
2
3
4
5
6
7
8
9
10
11
<script type="text/javascript">
     function box(num){      //按值传递
         num+=10;
         return num;
     }
 
     var num = 10;
     var result = box(num);
     alert(result);  //如果是按引用传递,那么函数里的num会成为类似全局变量,把外面的number替换掉
     alert(num);    //也就是说,最后应该输出20(这里输出10)
</script>

js没有按引用传递的,如果存在引用传递的话,那么函数内的变量将是全局变量,在外部也可以访问。但这明显是不可能的。

XSS的攻击场景

  • 反射型

    这类攻击方式主要借助URL来实施。URL的构成分为协议、域名、端口、路径、查询几部分构成。如图所示:

图片 6

  • XSS往往在“查询”部分发现漏洞构造攻击代码实施攻击,所谓“反射”可以理解为hacker并不会直接攻击客户,而是通过URL植入代码通过服务器获取并植入到用户页面完成攻击。攻击流程图如下:

图片 7

  • 存储型

    存储型攻击方式和反射型最大的区别就是不通过URL来传播,而是利用站点本身合法的存储结构,比如评论。任何用户都可以通过站点提供的接口提交评论内容,这些评论内容都被存储到服务器的数据库。当用户访问这些评论的时候,服务器从数据库提取内容插入到页面反馈给用户。如果评论内容本身是具备攻击性内容,用户无一幸免。攻击流程图如下:

图片 8

  • 从上下两个流程图来看,反射型和存储型的攻击方式是本质不同的,前者需要借助各种社交渠道传播具备攻击的URL来实施,后者通过网站本身的存储漏洞,攻击成本低很多,而且伤害力更大。

执行环境及作用域

执行环境是javascript中最为重要的概念之一,执行环境定义了变量或函数有权访问其他数据。

全局执行环境是最外围的执行环境,在web浏览器中,全局执行环境是window对象,因此,所有的全局变量的函数都是作为window的属性和方法创建的。

JavaScript

<script type=”text/javascript”> var name = “Jack”; //定义全局变量
function setName(){ return “trigkit4”; } alert(window.name);
//全局变量,最外围,属于window属性 alert(window.setName());
//全局函数,最外围,属于window方法 </script>

1
2
3
4
5
6
7
8
9
<script type="text/javascript">
      var name = "Jack";           //定义全局变量
      function setName(){
          return "trigkit4";
      }
 
      alert(window.name);        //全局变量,最外围,属于window属性
      alert(window.setName());  //全局函数,最外围,属于window方法
</script>

当执行环境内的代码执行完毕后,该环境被销毁,保存其中的变量和函数也随之销毁,如果是全局环境,需所有程序执行完毕或网页完毕后才会销毁。

XSS的工作原理

不管是反射型还是存储型,服务端都会将JavaScript当做文本处理,这些文本在服务端被整合进html文档中,在浏览器解析这些文本的过程也就是XSS被执行的时候。

从攻击到执行分为以下几步:

  1. 构造攻击代码
  2. 服务端提取并写入HTML
  3. 浏览器解析,XSS执行

去掉var的局部变量

JavaScript

<script type=”text/javascript”> var name = “Jack”; function
setName(){ name = “trigkit4”; //去掉var变成了全局变量 } setName();
alert(name);//弹出trigkit4 </script>

1
2
3
4
5
6
7
8
9
<script type="text/javascript">
      var name = "Jack";
      function setName(){
          name = "trigkit4";   //去掉var变成了全局变量
      }
 
      setName();
      alert(name);//弹出trigkit4
</script>
构造攻击代码

hacker在发现站点对应的漏洞之后,基本可以确定是使用“反射型”或者“存储型”。对于反射型这个很简单了,执行类似代码:

图片 9

大家知道很多站点都提供搜索服务,这里的item字段就是给服务端提供关键词。如果hacker将关键词修改成可执行的JavaScript语句,如果服务端不加处理直接将类似代码回显到页面,XSS代码就会被执行。

这段代码的含义是告诉浏览器加载一张图片,图片的地址是空,根据加载机制空图片的加载会触发Element的onerror事件,这段代码的onerror事件是将本地cookie传到指定的网站。

很明显,hacker可以拿到“中招”用户的cookie,利用这个身份就可以拿到很多隐私信息和做一些不当的行为了。

对于存储型直接通过读取数据库将内容打到接口上就可以了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注