什么是同源?如果两个页面拥有相同的协议(scheme)、域名(host)和端口(port)(http默认port80,https默认端口号443),那么这两个页面具有相同的源。
同源策略:是浏览器提供的一个安全策略。
同源策略主要表现在 DOM、Web 数据和网络这三个层面。
第一个,DOM 层面。同源策略限制了来自不同源的 JavaScript 脚本对当前 DOM 对象读和写的操作。(解决:跨文档消息机制:通过window.postMessage 的 JavaScript 接口来和不同源的 DOM 进行通信。)
第二个,数据层面。同源策略限制了不同源的站点读取当前站点的 Cookie、IndexDB、LocalStorage 等数据。
第三个,网络层面。同源策略限制了通过 XMLHttpRequest 等方式将站点的数据发送给不同源的站点。
什么是跨域?同源指的是两个url的协议(scheme)、域名(host name)、端口(port)一致,反之则是跨域。出现的根本原因:由浏览器的同源策略导致。
拦截是如何发生的?
当xhr.send被调用时,即Ajax准备发送请求时,还只是在渲染进程中,浏览器给每个渲染进程装进了沙箱,在沙箱中的渲染进程是无法发送网络请求的,需通过IPC将数据传给浏览器主进程,由主进程发起网络请求。服务端处理完数据后将数据返回,主进程检查到跨域,且没有cors响应头,将响应体全部丢掉,并不会发送给渲染进程。达到了拦截数据的目的。
如何解决跨域?
实现跨域数据请求有几种解决方案:JSONP、CORS、nginx反向代理(通过自家服务器访问别的服务器再响应回自家客户端)、websocket、iframe(诸多不便)。ranges’ 跨域解决方案
脚手架配置代理
JSONP:
注意JSONP和Ajax之间没有任何关系,不能把JSONP请求数据的方式叫做ajax,因为JSONP没有用到XMLHttpRequest这个对象。
JSONP的实现原理:JSONP是JSON的一种“使用模式”。
注意这里强调函数调用,从服务器返回一个函数的调用,在客户端执行回调,客户端决定调用哪个函数,通过查询字符串的形式(传入?callback=函数名)。
手写JSONP(封装JSONP):
function jsonp(url,params,callback){
var script=document.createElement('script');
var fnName='myJsonp'+Math.random().toString().replace('.','');//保证每次请求的方法都不会重复
//window[fnName]=obj.callback.name;//.后面不能跟变量,只能跟属性,所以用中括号
var params='';
for(let key in params){
params+='&'+key+'='+params[key];//&name='lisi'&age=19
}
script.src=url+'?callback='+fnName+params;
document.body.appendChild(script);
script.onload=function(){
document.body.removeChild(script);
}
}
jsonp({
url:'http://localhost:3001/better',
params:{
name:'lisi',
age:19
},
callback:function(data){
console.log(data);
}
})
使用JSONP的风险:
JSONP安全风险
JSONP劫持(属于CSRF漏洞)(jsonp劫持就是攻击者获取了本应该传给网站其他接口的数据)(通过JSONP技术可以实现数据的跨域访问,必然会产生安全问题,如果网站B对网站A的JSONP请求没有进行安全检查直接返回数据,则网站B 便存在JSONP 漏洞,网站A 利用JSONP漏洞能够获取用户在网站B上的数据。)
CORS(cross origin resource sharing跨域资源共享):
是W3C的一个标准,需要浏览器和服务器的共同支持,主要是服务器端响应头中做一些改动,设置哪些客户端可以访问服务器以及设置客户端可以以哪种方式(get/post)访问服务器。
简单了解一下简单请求与非简单请求:浏览器根据请求方法和请求头的特定字段,将请求做了分类,满足以下三个条件的属于简单请求:1,请求方法为GET、POST、HEAD。2,请求头的取值范围:Accept Accept-Language Content-Language Content-Type(只限于三个值:application/x-www-form-urlencoded,multipart/form-data,text/plain)。以外的属于非简单请求。
简单请求:请求发出去之前,浏览器做了什么?
它会自动在请求头当中,添加一个Origin字段,用来说明请求来自哪个源。服务器拿到请求之后,在回应时对应地添加Access-Control-Allow-Origin字段,如果Origin不在这个字段的范围中,那么浏览器就会将响应拦截。
因此,Access-Control-Allow-Origin字段是服务器用来决定浏览器是否拦截这个响应,这是必需的字段。与此同时,其它一些可选的功能性的字段,用来描述如果不会拦截,这些字段将会发挥各自的作用。
Access-Control-Allow-Credentials。这个字段是一个布尔值,表示是否允许发送 Cookie,对于跨域请求,浏览器对这个字段默认值设为 false,而如果需要拿到浏览器的 Cookie,需要添加这个响应头并设为true, 并且在前端也需要设置withCredentials属性:
let xhr = new XMLHttpRequest();
xhr.withCredentials = true;
Access-Control-Expose-Headers。这个字段是给 XMLHttpRequest 对象赋能,让它不仅可以拿到基本的 6 个响应头字段(包括Cache-Control、Content-Language、Content-Type、Expires、Last-Modified和Pragma), 还能拿到这个字段声明的响应头字段。比如这样设置:
Access-Control-Expose-Headers: aaa//在前端可以通过 XMLHttpRequest.getResponseHeader('aaa') 拿到 aaa 这个字段的值
非简单请求:非简单请求相对而言会有些不同,体现在两个方面: 预检请求和响应字段。为什么会有预检请求?因为复杂请求对服务器有一定的要求,如果服务器不同意预检请求的话,那么在返回的头部字段里面就会校验失败,预检请求校验失败了之后后面的请求也就不会发送了。
CORS请求和简单请求一样,浏览器自动加上Origin字段,服务端响应头返回Access-Control-Allow-Origin:
代理服务器:
正向代理、反向代理。
正向代理帮助客户端访问客户端自己访问不到的服务器,然后将结果返回给客户端。
反向代理拿到客户端的请求,将请求转发给其他的服务器,主要的场景是维持服务器集群的负载均衡,换句话说,反向代理帮其它的服务器拿到请求,然后选择一个合适的服务器,将请求转交给它。
因此,两者的区别就很明显了,正向代理服务器是帮客户端做事情,而反向代理服务器是帮其它的服务器做事情。
总结:
支持页面中的第三方资源引用和 CORS 也带来了很多安全问题,其中最典型的就是 XSS 攻击。
什么是XSS攻击?XSS 全称是 Cross Site Scripting,‘跨站脚本攻击’。XSS攻击是指黑客往HTML文件或者DOM中注入恶意脚本。
恶意脚本能做的事情:
常见的注入恶意脚本的方式:存储型XSS攻击、反射性XSS攻击、基于DOM的XSS攻击。
1,存储型XSS攻击
攻击步骤:
首先黑客利用站点漏洞将一段恶意 JavaScript 代码提交到网站的数据库中;
然后用户向网站请求包含了恶意 JavaScript 脚本的页面;
当用户浏览该页面的时候,恶意脚本就会将用户的 Cookie 信息等数据上传到恶意服务器
2,反射型XSS攻击
在一个反射型 XSS 攻击过程中,恶意 JavaScript 脚本属于用户发送给网站请求中的一部分,黑客通过各种方式诱导用户去点击恶意链接,随后网站把恶意 JavaScript 脚本返回给用户。
Web 服务器不会存储反射型 XSS 攻击的恶意脚本,这是和存储型 XSS 攻击不同的地方。
3,基于DOM的XSS攻击
基于 DOM 的 XSS 攻击是不牵涉到页面 Web 服务器的。具体来讲,黑客通过各种手段将恶意脚本注入用户的页面中,比如通过网络劫持在页面传输过程中修改 HTML 页面的内容,这种劫持类型很多,有通过 WiFi 路由器劫持的,有通过本地恶意软件来劫持的,它们的共同点是在 Web 资源传输过程或者在用户使用页面的过程中修改 Web 页面的数据。
4,mutation-based xss
如何阻止XSS攻击?
我们知道存储型 XSS 攻击和反射型 XSS 攻击都是需要经过 Web 服务器来处理的,因此可以认为这两种类型的漏洞是服务端的安全漏洞。而基于 DOM 的 XSS 攻击全部都是在浏览器端完成的,因此基于 DOM 的 XSS 攻击是属于前端的安全漏洞。
但无论是何种类型的 XSS 攻击,它们都有一个共同点,那就是首先往浏览器中注入恶意脚本,然后再通过恶意脚本将用户信息发送至黑客部署的恶意服务器上。
所以要阻止 XSS 攻击,我们可以通过阻止恶意 JavaScript 脚本的注入和阻止恶意消息的发送来实现。
常见策略:
当然除了以上策略之外,我们还可以通过添加验证码防止脚本冒充用户提交危险操作。而对于一些不受信任的输入,还可以限制其输入长度,这样可以增大 XSS 攻击的难度。
什么是CSRF攻击?CSRF 英文全称是 Cross-site request forgery,所以又称为“跨站请求伪造”,是指黑客引诱用户打开黑客的网站,在黑客的网站中,利用用户的登录状态发起的跨站请求。简单来讲,CSRF 攻击就是黑客利用了用户的登录状态,并通过第三方的站点发起请求。
通常当用户打开了黑客的页面后,黑客有三种方式去实施 CSRF 攻击:
1,自动发起Get请求
举例,在黑客的页面中,有一张图片的src对应的链接是一个转账的api,当用户被引诱进入了黑客的页面,页面被加载的时候,浏览器会自动发起img的资源请求,同时,借用用户的登录状态,就完成了这个转账的操作。
2,自动发起POST请求
举例,在黑客的页面中,有一个隐藏的表单,表单的内容为转账的api,当用户进入这个页面,表单被自动提交,服务器就会执行转账操作。
3,引诱用户点击链接
举例,通过引诱用户点击某个黑客的链接,该链接为转账的api,一旦点击链接,服务器就会执行转账操作。
和 XSS 不同的是,CSRF 攻击不需要将恶意代码注入用户的页面,因此黑客是无法通过 CSRF 攻击来获取用户页面数据的;仅仅是利用服务器的漏洞和用户的登录状态来实施攻击,所以要提高服务器安全性。
如何防止CSRF攻击?
发起 CSRF 攻击的三个必要条件:
第一个,目标站点一定要有 CSRF 漏洞;
第二个,用户要登录过目标站点,并且在浏览器上保持有该站点的登录状态;
第三个,需要用户打开一个第三方站点,可以是黑客的站点,也可以是一些论坛。
要让服务器避免遭受到 CSRF 攻击,通常有以下几种途径:
SQL injection
DOS攻击:
DDOS:消耗带宽
网络安全协议HTTPS(超文本传输安全协议)
HTTP是明文传输,使用 HTTP 传输的内容很容易被中间人窃取、伪造和篡改,通常我们把这种攻击方式称为中间人攻击。
所以在 HTTP 协议栈中引入安全层(HTTP+加密+认证+完整性保护=HTTPS):
从图中我们可以看出 HTTPS 并非是一个新的协议,通常 HTTP 直接和 TCP 通信,HTTPS 则先和安全层通信,然后安全层再和 TCP 层通信。也就是说 HTTPS 所有的安全核心都在安全层,它不会影响到上面的 HTTP 协议,也不会影响到下面的 TCP/IP,因此要搞清楚 HTTPS 是如何工作的,就要弄清楚安全层是怎么工作的。总的来说,安全层有两个主要的职责:对发起 HTTP 请求的数据进行加密操作和对接收到 HTTP 的内容进行解密操作。
第一版:使用对称加密(加密解密速度快)
所谓对称加密是指加密和解密都使用的是相同的密钥。密钥在传输时也会被黑客截获。
这样浏览器端和服务器端都有相同的 client-random 和service-random 了,然后它们再使用相同的方法将 client-random 和 service-random混合起来生成一个密钥 master secret,有了密钥 master secret 和加密套件之后,双方就可以进行数据的加密传输了。
第二版:使用非对称加密(速度慢、中间人攻击)
有公钥和私钥。先传公钥过去(相当于保险箱),小蓝手里的保险箱钥匙就是私钥,公钥(保险箱)谁都可以获取到,但是经过公钥加密的内容(保险箱里的信件)只有私钥可以解开。
小蓝相当于发送公钥的服务器。
中间人攻击见下图:
第三版:对称加密和非对称加密搭配使用
第一版中对称加密的密钥不是会被截获嘛,我们先用非对称加密来进行密钥交换,然后传输数据阶段依然使用对称加密通讯。
到此为止,服务器和浏览器就有了共同的 client-random、service-random 和 pre-master,然后服务器和浏览器会使用这三组随机数生成对称密钥,因为服务器和浏览器使用同一套方法来生成密钥,所以最终生成的密钥也是相同的。
有了对称加密的密钥之后,双方就可以使用对称加密的方式来传输数据了。
第四版:添加数字证书(验证服务器身份)
混合加密还会存在的问题:
服务器发送给浏览器的公钥,路上可能会被黑客劫持,替换成黑客自己的公钥,所以服务器需要向浏览器证明自己的身份,这样浏览器才能放心使用服务器发来的公钥给数据加密。
相较于第三版的 HTTPS 协议,这里主要有两点改变:
数字证书的申请过程:服务器生成一对公钥和私钥,私钥自己保存,通过公钥+企业+网站信息去CA机构申请证书。CA机构通过全方位的验证给这个网站颁发证书,证书内容包括企业信息、证书有效期、证书编号等,首先 CA 使用 Hash 函数来计算网站提交的明文信息,并得出信息摘要;然后 CA 再使用CA的私钥对信息摘要进行加密,加密后的密文就是 CA 颁给网站的数字签名。
浏览器校验证书的流程:浏览器接收到数字证书之后,会对数字证书进行验证。首先浏览器读取证书中相关的明文信息,采用 CA 签名时相同的 Hash 函数来计算并得到信息摘要 A;然后再利用对应 CA 的公钥(内置于操作系统或浏览器中)解密签名数据,得到信息摘要 B;对比信息摘要 A 和信息摘要 B,如果一致,则可以确认证书是合法的,即证明了这个服务器是网站的;同时浏览器还会验证证书相关的域名信息、有效时间等信息。
什么是数字证书?相当于网站的“身份证”,CA机构相当于颁发身份证的“国家”。数字证书中包含了网站域名、证书持有者、有效期、颁发机构、服务器公钥、hash算法。
什么是数字签名?相当于盖的章。对公钥+颁发机构+服务方提供的信息生成一个信息,再对该信息使用hash函数生成一个信息摘要,然后CA机构用私钥对信息摘要进行加密,加密后的密文就是数字签名。
数字证书作用:一、通过数字证书向浏览器证明服务器的身份;二、数字证书里面包含了服务器的公钥。
HTTPS握手过程:
HTTPS(TLS握手过程)&TCP协议(三次握手四次挥手)
HTTPS连接中接收/发送HTTP数据包会怎么样?
会怎么样:
HTTPS会不高兴,浏览器也会不高兴。
阻止掉HTTP的AJAX请求,然后报一个Mixed Content的错误(黄色的警告)。
引入一个HTTP请求的 js 文件,会被浏览器直接 block 掉。
解决方案:
相对协议:将URL的协议(http、https)去掉,只保留//及后面的内容。
iframe:使用 iframe 的方式引入 http 资源
浏览器的单进程架构的不足:
浏览器本身的漏洞是单进程浏览器的一个主要问题,如果浏览器被曝出存在漏洞,那么在这些漏洞没有被及时修复的情况下,黑客就有可能通过恶意的页面向浏览器中注入恶意程序,其中最常见的攻击方式是利用缓冲区溢出,不过需要注意这种类型的攻击和 XSS 注入的脚本是不一样的。XSS 攻击只是将恶意的 JavaScript 脚本注入到页面中,虽然能窃取一些 Cookie 相关的数据,但是 XSS 无法对操作系统进行攻击。而通过浏览器漏洞进行的攻击是可以入侵到浏览器进程内部的,可以读取和修改浏览器进程内部的任意内容,还可以穿透浏览器,在用户的操作系统上悄悄地安装恶意软件、监听用户键盘输入信息以及读取用户硬盘上的文件内容。
浏览器的多进程架构:
将渲染进程和操作系统隔离的这道墙就是安全沙箱。
浏览器中的安全沙箱是利用操作系统提供的安全技术,让渲染进程在执行过程中无法访问或者修改操作系统中的数据,在渲染进程需要访问系统资源的时候,需要通过浏览器内核来实现,然后将访问的结果通过 IPC 转发给渲染进程。安全沙箱最小的保护单位是进程。因为单进程浏览器需要频繁访问或者修改操作系统的数据,所以单进程浏览器是无法被安全沙箱保护的,而现代浏览器采用的多进程架构使得安全沙箱可以发挥作用。
我们知道安全沙箱能限制进程对操作系统资源的访问和修改,这就意味着如果要让安全沙箱应用在某个进程上,那么这个进程必须没有读写操作系统的功能,比如读写本地文件、发起网络请求、调用 GPU 接口等。
浏览器内核和渲染进程各自职责:
通过该图,我们可以看到由于渲染进程需要安全沙箱的保护,因此需要把在渲染进程内部涉及到和系统交互的功能都转移到浏览器内核中去实现。