浏览器的缓存、跨域与安全

11 阅读11分钟

浏览器的资源一般存储在哪里

  1. 资源存储的位置一共有三种,从高到低依次是Service worker、Memory Cache、Disk Cache
  2. service worker:运行在主线程之外,可以完成离线缓存、消息推送、网络代理的功能。可以自由控制缓存哪些文件,怎么读取缓存。当 Service Worker 没有命中缓存的时候,需要去调用 fetch 函数获取数据。
  3. Memory Cache:内存缓存,它的效率最快,但是它会随着进程的释放而释放。一旦关闭tab页面,内存的缓存也被释放了。
  4. Disk Cache: 存储在硬盘的缓存,对比于内存缓存,读取的速度慢一些,特点是容量与时效性上更长。它会根据 HTTP请求头中的字段判断哪些资源需要缓存,哪些资源可以不请求直接使用,哪些资源已经过期需要重新请求。

浏览器的本地缓存?

  1. Cookie:是服务端记录用户状态一种方式;由服务端生成,客户端存储。在每次同源请求都会在请求头带上Set-Cookie,如Set-Cookie:name=value,domain=.;path=..。它的大小只有4KB,只能被同源的页面共享,生存周期由Expired控制;
  2. LocalStorage:持久化存储,除非自己手动删除;最多允许存储5MB的内容,遵循同源策略,只能被同源页面访问共享;
  3. SessionStorage:会话存储,一般存储5M大小的数据,并且遵循同源策略。页面刷新存储的信息会在,页面关闭存储的信息会消失;
  4. 虚拟内存存储,例如:全局变量、vuex、redux:页面刷新或者关闭,存储的信息都会释放;
Cookie有哪些字段,作用分别是什么?
  1. name value domain path expired secure HttpOnly
  2. domain是域名、path是路径,domain和path一起限制了cookie能够被哪些url访问;
  3. expires指定了cookie失效的时间;
  4. secure规定了cookie只能在确保安全的情况下传输;
  5. HttpOnly规定了cookie只能被服务器访问,不能使用js脚本访问;
LocalStorage与SessionStorage区别
  1. 共同点:都是保存在浏览器端,大小5M,都遵循同源策略。
  2. 不同点:在于生命周期与作用域的不同,作用也不同。
  3. LocalStorage因为是持久化,在项目可以保存用户选择的主题。
  4. SessionStorage具有时效性,可以用来存储一些网站的游客登录的信息,还有临时的浏览记录的信息。当关闭网站之后,这些信息也就随之消除了。

对浏览器缓存机制的了解?

缓存”存储在哪了? ① 内存缓存(MemoryCache):页面关闭,存储的东西会消失; ② 磁盘缓存(Disk Cache):持久存储,可以根据关键HTTP缓存头,减少网络请求次数。

强缓存
  1. 浏览器第一次加载资源,服务器返回Cache-Control/Expires,浏览器保存并缓存文件。
  2. 当请求再次发出时,浏览器会根据其中的 expires:Sun,15 ay 2025 20:14:22 GMTcache-control:max-age=2592000 ,判断目标资源是否“命中”强缓存。
  3. 若命中则直接从缓存中获取资源,不会再与服务端发生通信。 命中强缓存的情况下,返回的 HTTP 状态码为 200。
协商缓存
  1. 第一次请求页面,向服务端发起请求,如果需要设置协商缓存,服务器就会在响应头返回Last-Modified/Etag,浏览器看到标识后会把标识与资源缓存起来。
  2. 第二次请求也会向服务器发送请求,在请求头中基于If-Modified-Sine/If-None-Match分别把存储的Last-Modified/Etag值传递给服务器。
  3. 服务器获取后比较: 如果资源没有更新过则时间或标识是一致的,服务器返回304,则从本地缓存获取;如果资源更新过则时间或标识是不一样的,服务器返回200、请求的文件以及最新的Last-Modified/ETag,浏览器把标识与资源缓存起来。
  4. 强缓存与协商缓存区别?

a. 是否向向服务器发起请求:强缓存如果缓存资源有效则直接使用,不用向服务器发起请求;协商缓存会先向服务器发送一个请求,如果资源没有发生修改,则返回一个 304 状态;
b. 设置方式:强缓存策略通过两种方式来设置,分别是http头信息中的Expires属性和Cache-Control属性。两种都存在时候Cache-Control的优先级要高于Expires;协商缓存通过两种方式来设置,分别是http头信息中的EtagLast-Modified属性。

什么是同源策略?

  1. 浏览器网络请求时,有一个同源策略机制:就是需要协议、域名、端口三者一致。
  2. 目的是为了保证用户信息的安全,对js脚本的一种限制。对于一般的img、或者script脚本请求都不会有跨域的限制
  3. 同源策略主要限制了什么? a. 当前域下的js不能访问其他域的cookie、storage; b. 当前域下的js不能操作其他域的dom; c. 当前域下的ajax不能发送跨域请求;
  4. 跨域其实不是请求发不出去,请求发出去了且服务器也返回数据,但是由于同源限制所以浏览拦截了。

怎么解决跨域问题?

1. CORS
  1. 全称跨域资源共享(Cross-Origin Resource Sharing)用于控制浏览器校验跨域请求的一套规范,服务器依照CORS规范,添加特定响应头来控制浏览器校验。
  2. 整体思路:服务器在给出响应时,通过添加Access-Control-Allow-Origin响应头,来明确表达允许某个源发起跨域请求,随后浏览器在校验时通过。
  3. CORS会把请求分为两类,分别是:① 简单请求、② 复杂请求。简单请求有get post head;HTTP的头信息Content-Type只限于三个值:application/x-www-form-urlencodedmultipart/form-datatext/plain
简单请求过程
  1. 发出跨域请求后,浏览器会自动向请求头添加origin字段,用来说明这个请求来自哪个源;
  2. 服务器会根据这个判断是否在许可范围内,如果Origin指定的域名在许可范围内,则服务器响应头有以下:Access-Control-Allow-OriginAccess-Control-Allow-HeadersAccess-Control-Allow-Crediential:表示是否允许发生Cookie;
  3. 不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器收到响应发现没有包含Access-Control-Allow-Origin字段就会拦截。
// 处理实际请求
app.get('/students', (req, res) => {
  // 设置允许的跨域请求源
  res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500')
    // 设置允许的请求方法
  res.setHeader('Access-Control-Allow-Methods', 'GET')
  // 设置允许暴露给客户端的响应头
  res.setHeader('Access-Control-Allow-Headers', 'abc')
  console.log('有人请求/students了')
  // 发送响应数据
  res.send(students)
})
复杂请求过程

先发起OPTIONS请求,如果通过预检,再发起实际的跨域请求。预检请求在实际跨域请求之前发出,是由浏览器自动发起的。

  1. 预请求发送内容:请求方法是OPTIONS,表示查询;头信息需要有origin、Access-Control-Request-Method、Access-Control-Request-Headers
  2. 服务器在收到浏览器的预检请求之后,会根据头信息的三个字段来进行判断是否允许跨源请求。如果可以则会返回:Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers、Access-Control-Max-Age本次预检的有效期;
  3. 浏览器监测到后会将实际请求发送到服务器,然后服务器返回我们需要的资源;如果没有,就是不同意这个预检请求,浏览器会阻止跨域访问,实际的请求永远不会被发送。
// nodejs处理预检请求
app.options('/students', (req, res) => {
  // 设置允许的跨域请求源
  res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5100')
  // 设置允许的请求方法
  res.setHeader('Access-Control-Allow-Methods', 'GET')
  // 设置允许的请求头
  res.setHeader('Access-Control-Allow-Headers', 'school')
  // 设置预检请求的缓存时间(可选)
  res.setHeader('Access-Control-Max-Age', 7200)
  // 发送响应
  res.send()
})
2. proxy代理
  1. 通过开启一个代理服务器,实现数据的转发。
  2. 原理就是利用服务器与服务器之间不存在跨域来实现。在本地启动一个服务,代理服务器与前端所处的协议主机端口一样,它收到本次的请求把请求转发给目的服务器,等到收到返回数据再返回给前端;
  3. vue-cli开启代理服务器,在vue.config.js配置devServer的proxy选项。如果在proxy里面加上"/api":{target:''},那么以"/api"开始的请求就被发送到代理服务器。
devServer:{
  //配置跨域代理,可以配置对多台服务器的代理
  proxy:
    //以"/api"开始的请求,都发送到代理服务器
    "/api":{
        target:"https://www.baidu.com/aa",
        changeOrigin:true, //改变origin源
        pathRewrite:{"^/api":""},
    }
    //以"/api1"开始的请求,都发送到代理服务器
    "/api1":{
      target:"https://nnn.baidu.com/bb",
      changeOrigin:true,
      pathRewrite:{"^/api1":""}
    }
}
3. nginx代理跨域
  1. nginx配置解决iconfont跨域
  2. 跨域访问js、css、img等常规静态资源被同源策略许可,但iconfont字体文件不行,location / {add_header Access-Control-Allow-Origin *;}

浏览器安全机制?

XSS攻击
  1. 是什么?XSS(Cross Site Scripting)跨站脚本攻击,是使用注入恶意脚本的攻击手段。XSS攻击是指黑客往HTML文件中或者DOM中注入恶意脚本,从而在用户浏览页面时利用注入的恶意脚本对用户实施攻击的一种手段。
  2. 页面被注入了恶意 JavaScript 脚本,恶意脚本可以:可以窃取 Cookie 信息;监听用户行为,比如获取用户输入的信用卡等信息;在页面内生成浮窗广告;
  3. 种类:存储型XSS攻击;反射型XSS攻击;基于DOM的XSS攻击,这三种攻击方式的共同点是都需要往用户的页面中注入恶意脚本,然后再通过恶意脚本将用户数据上传到黑客的恶意服务器上。
  4. 阻止XSS攻击:① 服务器对输入的脚本进行过滤和转码,如过滤<script>标签;② 使用HttpOnly属性,当HttpOnly被设置为true的时候,无法通过js脚本读取到cookie的数据,一些重要的数据设置HttpOnly标志;③ 利用CSP:比如限制加载其他域下的资源文件;
CSRF攻击
  1. 是什么?(Cross-site request forgery)跨站请求伪造,利用用户的登录状态发起的跨站请求,并通过第三方站点来做一些坏事。
  2. 需满足三个条件:① 目标站点一定要有CSRF漏洞;② 用户要登录过目标站点,并且在浏览器上保持有该站点的登录状态;③ 用户需要打开第三方站点,引诱用户点击链接:比点击美女图片下载地址,而这个下载地址实际上是黑客用来转账的接口,一旦用户点击了这个链接并登录了xx软件,那么软件的钱就被转到黑客账户上了。
  3. 防止CSRF攻击,主要是提升服务器的安全性:

a. 利用好Cookie的sameSite属性,HTTP响应头中,通过set-cookie字段设置Cookie,可以带上SameSite选项,Strict值浏览器会完全禁止第三方Cookie;Lax值在第三方站点中使用Post方法,或者通过img、iframe等标签加载的URL,这些场景都不会携带Cookie;
b. 验证请求的来源站点,使用HTTP请求的RefererOrigin属性。Referer记录了该HTTP请求的来源地址;
c. 采用CSRF的Token来验证;

浏览器的垃圾回收机制?

  1. 是什么是垃圾回收? js代码运行时,需要存储空间来存储变量和值。js它有自动的垃圾回收机制,会定期对那些不再使用的变量、对象所占用的内存进行释放。
  2. 垃圾回收的方式? 标记清除与引用计数。
  3. 标记清除?是浏览器最常用的垃圾回收方式,当变量进入执行环境时候,会标记这个变量进入环境,因为正被使用,所以变量不能回收;变量离开环境时候,被标记离开环境,这时变量会被内存释放。
  4. 怎么减少垃圾回收?对象尽量复用,对于不再使用的对象,就将其设置为 null,尽快被回收。

链接

浏览器工作原理与实践