浏览器安全
xss
概念
恶意代码注入攻击,盗取用户信息等。
攻击类型:存储型、反射型、DOM型。
存储型的恶意代码存在数据库里,当用户访问的页面有恶意代码的数据时,会执行脚本,做一些恶意操作,比如窃取数据、冒充用户行为
反射型的恶意代码存在URL里,用户打开url,服务器将恶意代码从url中取出并执行,调用目标网站接口执行将数据发送到攻击者服务器中
DOM的XSS是浏览器完成,上面两种都是服务端完成。
如果防御
- 代码中做到充分的转义,
- 使用CSP。一种内容安全策略,可以配置白名单指定能够加载执行的外部资源
- csp开启方式:一种是设置 HTTP 首部中的 Content-Security-Policy,一种是设
meta标签的方式
- csp开启方式:一种是设置 HTTP 首部中的 Content-Security-Policy,一种是设
- 对一些敏感信息进行保护,比如cookie使用的http-only,验证码等。
CSRF
概念
跨站请求伪造攻击,利用cookie在同源请求中绕过用户登陆向服务器发送请求。
攻击类型:get类型、post类型、链接类型
如何防御
- 进行同源检测:通过refer判断是不是可以请求的页面
- 使用CSRF TOKEN进行验证
- 对cookie进行双重验证
- 设置cookie的时候设置samesite,限制cookie不能被第三方使用。
中间人攻击
攻击者和通讯的两端都建立联系,让两端以为在直接联系,在中间篡改信息
哪些可能引起安全问题
- 跨站脚本,XSS
- iframe的滥用
- 跨站点请求伪造(CSRF)
- 恶意第三方库
网络劫持有哪几种
- DNS劫持(违法)
- HTTP劫持(盛行),防护措施:https
进程与线程
概念
进程是资源分配的最小单位,线程是CPU调度的最小单位。
进程是运行在虚拟内存上的。
两者关系
- 线程执行出错,会导致进程崩溃
- 线程之间共享进程的数据
- 当一个进程关闭之后,操作系统会回收进程所占用的内存
- 进程之间的内容相互隔离。如果要通讯的话有单独的通讯机制
区别
- 切换时,资源、系统开销,进程都比较大、线程都比较小
- 通信,线程比较方便,进程比较麻烦需要通信机制
进程之间的通信
- 管道通信
- 消息队列通信
- 信号量通信
- 信号通信
- 共享内存通信
- 套接字通信
僵尸进程、孤儿进程
**僵尸进程:**子进程已结束父进程未结束,但父进程没有释放子进程的内存。这些子进程被叫做僵尸进程。
**孤儿进程:**父进程退出了,子进程还在运行。这些进程被叫做孤儿进程。释放方式:挂载在init进程上统一回收。
死锁
多个进程进行资源争夺出现僵局,(资源分为可剥夺资源、不可剥夺资源)
产生原因:
- 竞争资源:竞争不可剥夺资源和临时资源
- 进程间推进顺序非法。
chrome的浏览器包括:
- 1个浏览器主进程
- GPU进程
- 网络进程
- 多个渲染进程
- 多个插件进程
打开一个页面最少要 1-4 ,4个进程。 缺点:高资源占用;浏览器体系复杂,难以完全适配。
浏览器渲染进程中的线程有:GUI渲染线程、JS引擎线程、事件触发线程、定时器触发线程、异步http请求线程。
定时器触发请求:即setTimeout和setInterval;W3C在HTML标准中规定,定时器的定时时间不能小于4ms,如果是小于4ms,则默认为4ms。
浏览器之间多个标签页的通讯
通过中间件来进行通讯
- 利用网络,websocket协议
- 利用共享线程,shareWorker
- 监听localStorage,
- postMessage
service worker
运行在浏览器背后的独立线程。可用来实现缓存功能。 实现步骤:注册线程 => 监听到注册成功,缓存对应文件 => 拦截请求,如果文件已缓存,使用缓存,否则请求数据
浏览器缓存
强制缓存
浏览器初次请求页面,通过header头的 Expires 属性 和 Cache-Control 的设置来决定如何缓存资源。
- Expires 表示 资源过期时间;http1.0 提出;
- Cache-Control 是 http1.1 提出,由于 Expires 属性单一等缺点,出现这个属性。
- Cache-Control可设置的字段:
- public :表示可以被任何对象缓存
- private :表示只能用户浏览器缓存,禁止代理服务器缓存
- no-cache :对比服务器上的资源是否发生变化,如果未变化直接用缓存,会有协商缓存
- no-store : 完全禁止缓存,协商缓存
- max-age= :缓存最大有效期,单位为秒
- s-maxage= : 优先级高于max-age=和Expires,仅适用于CDN
- max-stale[=] : 表示用户愿意接受过期的资源,但不能超出给定的时间
- Cache-Control可设置的字段:
一般来说设置一种就可以缓存,但是 Cache-Control 的优先级要高于 Expires。 如果强制缓存,就会直接下载;
协商缓存
命中协商缓存的条件:
- max-age=xxx 过期了
- no-store
命中协商缓存后 服务器发现资源未变化,会返回304,浏览器直接使用副本;变化直接返回资源。
协商缓存也可以通过 http 头信息中的 Etag 和 Last-Modified 属性 来设置。
- Last-Modified :表示最后一次资源修改的时间;请求下一次会给服务器发送上次请求时文件修改的时间,以此来判断文件是否修改过。如果时间没变 返回 304;时间变了 返回新的资源。
- 缺点:如果在秒级修改多次,时间没变,文件也不会变
- Etag : 类似文件hash值,资源发生改变的时候,这个值也会改变。
- 缺点:如果考虑负载平衡不建议用这个值 Etag 和 Last-Modified同时出现的时候,Etag优先级高
强缓存和协商缓存区别
- 有缓存时,强缓存不会发送请求,协商缓存会发送一次请求
优点:可以减少请求,提高页面性能
点击刷新按钮或者按 F5、按 Ctrl+F5 (强制刷新)、地址栏回车有什么区别?
- 点击刷新按钮或者按
F5: 浏览器直接对本地的缓存文件过期,但是会带上If-Modifed-Since,If-None-Match,这就意味着服务器会对文件检查新鲜度,返回结果可能是 304,也有可能是 200。 - 用户按 Ctrl+F5(强制刷新): 浏览器不仅会对本地文件过期,而且不会带上If-Modifed-Since,If-None-Match,相当于之前从来没有请求过,返回结果是 200。
- 地址栏回车: 浏览器发起请求,按照正常流程,本地检查是否过期,然后服务器检查新鲜度,最后返回内容。
浏览器组成
理解: 展示页面。分为shell(菜单、工具栏等)和内核(识别程序)两部分
浏览器内核
- 渲染引擎
- js引擎
常见浏览器内核
- Trident:IE浏览器内核,久不维护,基本被废弃
- Gecko:火狐和flock的内核,功能强大但耗费内存
- Presto:Opera 曾经的内核,速度很快,但是丢失了一部分的兼容性
- Webkit:safari的内核,速度较快,兼容性也低;是KHTML的一个分支
- Blink:GOOGLE,Opera,共同的引擎,也是KHTML的一个分支
常见浏览器所用内核
- IE 浏览器内核:Trident 内核,也是俗称的 IE 内核;
- Chrome 浏览器内核:统称为 Chromium 内核或 Chrome 内核,以前是 Webkit 内核,现在是Blink内核;
- Firefox 浏览器内核:Gecko 内核,俗称 Firefox 内核;
- Safari 浏览器内核:Webkit 内核;
- Opera 浏览器内核:最初是自己的 Presto 内核,后来加入谷歌大军,从 Webkit 又到了 Blink 内核;
- 360浏览器、猎豹浏览器内核:IE + Chrome 双内核;
- 搜狗、遨游、QQ 浏览器内核:Trident(兼容模式)+ Webkit(高速模式);
- 百度浏览器、世界之窗内核:IE 内核;
- 2345浏览器内核:好像以前是 IE 内核,现在也是 IE + Chrome 双内核了;
- UC 浏览器内核:这个众口不一,UC 说是他们自己研发的 U3 内核,但好像还是基于 Webkit 和 Trident ,还有说是基于火狐内核。
浏览器的主要组成部分
- 用户界面
- 浏览器引擎
- 呈现引擎
- 网络
- 用户界面后端
- js解释器
- 数据存储
浏览器渲染原理
浏览器渲染步骤
- 解析文档,将文档解析为带属性的 DOM 树。
- 解析CSS 将css解析为 cssM树
- 上面两个树,最后合成一个渲染树。只会有可见的元素,这个时候节点只知道大小颜色
- 生成渲染树后,根据渲染树推出节点的位置,这一步叫回流
- 然后对着渲染树进行绘制。 树不可能一次性生成完,而是生成一部分绘制一部分,有些可能还在下载。
浏览器渲染优化
- js的位置:不要讲script放在head、body中,放在
</body>前,还有异步加载方式 defer或者async - 针对css 有两种 link、@import。前者会增加线程下载,后者会阻塞渲染。style内嵌 直接渲染。
- cssom树,dom树的优化
- html文件代码层级不要太深
- 语义化标签
- cssD代码的层级,选择是从左向右解析的
- 减少回流和重绘:
- DOM 在低层次操作
- 不要用table布局
- 使用css表达式
- 少操作样式,尽量改类名
- 使用absolute或fixed。脱离文档流,改样式不会影响其他元素
- 避免频繁操作DOM,可以创建文档片段,加在文档里
- 不可见元素可以设置display:none,需要展示的时候展示出来
- 将相同的读操作或写操作放一起,不要穿插放,这样浏览器会把相同的操作执行回流一次(浏览器自身的优化:渲染队列)
渲染时遇到js如何处理
会阻塞渲染,直到js执行完; 如果有defer或async异步加载,defer会并行下载,DOM数据结束后执行。async会并行下载,下载后阻断渲染直接执行
文档预解析
Webkit 和 Firefox 做了优化,js执行时,另一个线程解析剩下的文档,比如外部资源等等。但不会解析dom树
css如何阻塞文档解析
js中有css样式会阻塞文档解析。这种情况下会先css解析,再js执行,再文档解析
优化关键渲染路径
(1)关键资源的数量。 (2)关键路径长度。 (3)关键字节的数量。
阻塞渲染的情况
- 多层级的dom树和css树
- 放在头部的js
浏览器本地存储
cookie
每个cookie大小不超过4kb,数量不能超过20个; 每次请求都会被携带
缺点:安全性
LocalStorage
特性:大小5MB,不会被清除,请求不会携带
缺点:1. IE8 下不支持;2. 隐私模式的浏览器无法读取; 3. 非同源页面 访问不到
SessionStorage
特性:大小5MB,请求不会携带,关闭标签页会被清除
IndexedDB
特性:内存大 250MB;同源策略;支持失败即回滚;异步,上面都是同步的;对象仓库,所有key都是唯一的;支持二进制存储
浏览器同源策略
同源策略
同源指的是:协议、端口号、域名必须一致。
不能跨域请求、不能获取缓存、不能操作dom
如何解决
- cors:浏览器服务器同时支持,
-
简单请求中解决跨域(简单请求:请求方式为HEAD、GET、POST之一;HTTP头信息只有Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type的几个)
- 在简单请求中,在服务器内,至少需要设置字段:Access-Control-Allow-Origin
-
非简单请求
- 先发送预检请求;请求通过解决跨域
- 预检请求时OPTIONS,头部信息带origin(必须)、Access-Control-Request-Method(必须)、Access-Control-Request-Headers
- 服务要设置的字段 'Access-Control-Allow-Origin' 'Access-Control-Allow-Methods' 'Access-Control-Allow-Headers'
- 减少OPTIONS的请求次数可以通过设置Access-Control-Max-Age(缓存时间);可以提高网页性能。
- 先发送预检请求;请求通过解决跨域
-
CORS中Cookie相关问题:
- 跨域请求携带cookie 需要在请求中设置 withCredentials
-
- JSONP
- jsonp的原理就是利用
<script>标签没有跨域限制,通过<script>标签src属性,发送带有callback参数的GET请求,服务端将接口返回数据拼凑到callback函数中,返回给浏览器,浏览器解析执行,从而前端拿到callback函数返回的数据。 - 缺点:
- 具有局限性, 仅支持get方法
- 不安全,可能会遭受XSS攻击
- jsonp的原理就是利用
- postMessage跨域
- 解决场景
- 页面和其打开的新窗口的数据传递
- 多窗口之间消息传递
- 页面与嵌套的iframe消息传递
- 上面三个场景的跨域数据传递
- postMessage(data,origin)
- 解决场景
- nginx代理跨域:
- 通过配置文件设置请求响应头Access-Control-Allow-Origin…等字段。
# proxy服务器
server {
listen 81;
server_name www.domain1.com;
location / {
proxy_pass http://www.domain2.com:8080; #反向代理
proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
index index.html index.htm;
# 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
add_header Access-Control-Allow-Origin http://www.domain1.com; #当前端只跨域不带cookie时,可为*
add_header Access-Control-Allow-Credentials true;
}
}
- nodejs 中间件代理跨域
node中间件实现跨域代理,原理大致与nginx相同,都是通过启一个代理服务器,实现数据的转发,也可以通过设置cookieDomainRewrite参数修改响应头中cookie中域名,实现当前域的cookie写入,方便接口登录认证。
- document.domain + iframe跨域:此方案仅限主域相同,子域不同的跨域应用场景。实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。
- location.hash + iframe跨域:
- window.name + iframe跨域
- WebSocket协议跨域
正向代理、反向代理
正向代理:客户端做代理,为隐藏客户端
反向代理:服务端做代理,为隐藏服务端ip
4. Nginx的概念及其工作原理
轻量级web服务器
浏览器事件机制
事件及事件模型
事件:交互事件
事件模型:
- DOM 0级事件:直接在dom对象上注册事件名称,就是DOM0写法。
- IE事件模型:两个阶段,先处理、后冒泡(从下往上)
- DOM 2级事件:三个阶段,先捕获(从上往下)找到目标元素,期间有事件就执行;到了目标元素就事件处理,然后冒泡
阻止冒泡: 普通浏览器使用:event.stopPropagation() IE浏览器使用:event.cancelBubble = true;
事件委托
概念:点击事件的冒泡机制,将事件委托到某个父节点上,父节点来执行方法;如列表
特点:减少内存消耗,动态绑定事件
局限性:focus、blur没有冒泡机制因此事件委托;mouseout、对性能消耗高
使用场景:
同步事件、异步事件
- 同步:同步方法执行时,会阻塞
- 异步:不阻塞后续操作
事件循环
js是单线程,在执行同步代码时,遇到异步代码,执行后不会等待返回,js会继续执行下一个任务,异步任务执行完毕后,会放到任务队列中等待执行。任务队列分微任务和宏任务,当当前执行栈中的任务执行完后, 会先将剩余的微任务压栈执行,然后是宏任务。
Event Loop 执行顺序如下所示:
- 首先执行同步代码,这属于宏任务
- 当执行完所有同步代码后,执行栈为空,查询是否有异步代码需要执行
- 执行所有微任务
- 当执行完所有微任务后,如有必要会渲染页面
- 然后开始下一轮 Event Loop,执行宏任务中的异步代码
宏任务、微任务
- 宏任务:定时器事件、script执行,UI渲染,I/O操作
- 微任务:promise、node的process.nextTick、MutationObserver
执行栈
可以把执行栈认为是一个存储函数调用的栈结构,遵循先进后出的原则。 当开始执行 JS 代码时,根据先进后出的原则,后执行的函数会先弹出栈,
栈有限制,放多了会爆栈
Node 中的 Event Loop 和浏览器中的有什么区别?process.nextTick 执行顺序?
事件触发的过程是怎样的
- 捕获,处理,冒泡 同时注册,会顺序执行
- stopPropagation,可以阻止向上冒泡、向下捕获
- stopImmediatePropagation 同样也能实现阻止事件,但是还能阻止该事件目标执行别的注册事件。
浏览器垃圾回收机制
- 新生代:两个空间,From,to。From内存用完了,将活得放到to,删掉from再换回来
- 老生代:
- 会出现的原因:用过新生代算法的、To的大小超过25%
- 标记清除法(过滤一些):某一空间没分块、空间被对象超过一定限制、空间不能保证新生代移到老生代;清除后会有碎片,将碎片压缩后,将可用的向另一端移动,清理掉不要的内存
内存泄露
- 无法回收的变量
- 一直被引用的变量。比如setInterval内部使用的外部变量
- DOM元素的引用
- 不合理的使用闭包,从而导致某些变量一直被留在内存当中