说到Web页面安全你会想到哪些问题呢?
什么是同源、什么是同源策略、同源策略的表现是什么?
浏览器出让了同源策略的哪些安全性?
跨域解决方案有哪些?
JSONP如何实现?
CORS你了解哪些?
针对Web页面安全有哪些常见的攻击手段(XSS、CSRF)?
说到浏览器网络安全你会想到哪些问题呢?
什么是请求报文?
什么是响应报文?
HTTP缺点
HTTPS基础知识点
HTTPS流程
说到浏览器系统安全你会想到哪些问题呢?
安全沙箱
img
2.1.1 同源
跨域本质其实就是指两个地址不同源,不同源的反面不就是同源,同源指的是:如果两个URL的协议、域名和端口号都相同,则就是两个同源的URL。
// 非同源:协议不同
http://www.baidu.com
https://www.baidu.com
// 同源:协议、域名、端口号都相同
http://www.baidu.com
http://www.baidu.com?query=1
2.1.2 同源策略
同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的加载的脚本如何能与另一个源的资源进行交互。其主要是为了保护用户信息的安全,防止恶意的网站窃取数据,是浏览器在Web页面层面做的安全保护。
2.1.3 同源策略的表现
既然同源策略是浏览器在Web页面层面做的保护,那么该层面哪些位置需要进行保护呢?总结下来主要包含三个层面:DOM层面、数据层面、网络层面。
DOM层面
同源策略限制了来自不同源的JavaScript脚本对当前DOM对象读和写的操作。
数据层面
同源策略限制了不同源的站点读取当前站点的Cookie、IndexedDB、localStorage等数据。
网络层面
同源策略限制了通过XMHttpRequest等方式将站点的数据发送给不同源的站点。
2.1.4 浏览器出让了同源策略的哪些安全性?
同源策略保证了浏览器的安全,但是如果将这三个层面限制的死死的,则会让程序员的开发工作举步维艰,所以浏览器需要在最严格的同源策略限制下做一些让步,这些让步更多了是在安全性与便捷性的权衡。其实跨域的方式就可以认为是浏览器出让了一些安全性或在遵守浏览器同源策略前提下所采取的一种折中手段。
2.2.1 DOM层面和数据层面分类
根据同源策略,如果两个页面不同源,无法互相操作DOM、访问数据,但是两个不同源页面之间进行通信是比较常见的情形,典型的例子就是iframe窗口与父窗口之间的通信。随着历史的车轮,实现DOM层面间通信的方式有多种,如下所示:
片段标识符
片段标识符其核心原理就是通过监听url中hash的改变来实现数据的传递,想法真的很巧妙。
// 父页面parentHtml.html
我是父页面
// 子页面childHtml.html
我是子页面
window.name
浏览器窗口有window.name属性,这个属性的最大特点是,无论是否同源,只要在同一个窗口里,前一个网页设置了这个属性,后一个网页可以读取它。如果需要实现父页面和跨域的子页面之间的通信,需要一个和父页面同源的子页面作为中介,将跨域的子页面中的信息传递过来。(好麻烦呀,强烈不推荐使用,此处就不写对应的代码啦)
document.domain
document.domain是存放文档的服务器的主机名,可通过手动设置将其设置成当前域名或者上级的域名,当具有相同document.domain的页面就相当于处于同域名的服务器上,如果其域名和端口号相同就可以实现跨域访问数据了。
postMessage(强烈推荐)
window.postMessage是HTML5新增的跨文档通信API,该API,允许跨窗口通信,不论这两个窗口是否同源。
// 父页面
我是父页面
// 子页面
我是子页面
2.2.2 网络层面
根据同源策略,浏览器默认是不允许XMLHttpRequest对象访问非同一站点的资源的,这会大大制约生产力,所以需要破解这种限制,实现跨域访问资源。目前广泛采用的主要有三种方式(注:该出不给出具体代码,后续会有专门的百题斩进行详细阐述):
2.2.2.1 通过代理实现
同源策略是浏览器为了安全制定的策略,所以服务端不会存在这样的限制,这样我们就可以将请求打到同源的服务器上,然后经由同源服务器代理至最终需要的服务器,从而实现跨域请求的目的。例如可以通过Nginx、Node中间件等。
2.2.2.2 JSONP的方式
JSONP是一种借助script元素实现跨域的技术,它并没有使用XMLHttpRequest对象,其能够实现跨域主要得益于script有两个特点:
(1)src属性能够访问任何URL资源,并不会受到同源策略的限制;
(2)如果访问的资源包含JavaScript代码,其会在下载后自动执行。
下面一起来实现一下JSONP
全局挂载一个接收数据的函数;
创建一个script标签,并在其标签的onload和onerror事件上挂载对应处理函数;
将script标签挂载到页面中,向服务端发起请求;
服务端接收传递过来的参数,然后将回调函数和数据以调用的形式输出;
当script元素接收到影响中的脚本代码后,就会自动执行它们。
function createScript(url, charset) {
const script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
charset && script.setAttribute('charset', charset);
script.setAttribute('src', url);
script.async = true;
return script;
}
function jsonp(url, onsuccess, onerror, charset) {
const hash = Math.random().toString().slice(2);
window['jsonp' + hash] = function (data) {
if (onsuccess && typeof(onsuccess) === 'function') {
onsuccess(data);
}
}
const script = createScript(url + '?callback=jsonp' + hash, charset);
// 监听加载成功的事件,获取数据,这个位置用了两个事件onload和onreadystatechange是为了兼容IE,因为IE9之前不支持onload事件,只支持onreadystatechange事件
script.onload = script.onreadystatechange = function() {
//若不存在readyState事件则证明不是IE浏览器,可以直接执行,若是的话,必须等到状态变为loaded或complete才可以执行
if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') {
script.onload = script.onreadystatechange = null;
// 移除该script的DOM对象
if (script.parentNode) {
script.parentNode.removeChild(script);
}
// 删除函数或变量
window['jsonp' + hash] = null;
}
};
script.onerror = function() {
if (onerror && typeof(onerror) === 'function') {
onerror();
}
}
// 添加标签,发送请求
document.getElementsByTagName('head')[0].appendChild(script);
}
2.2.2.3 CORS方式
跨域资源共享(CORS),该机制可以进行跨域访问控制,从而使跨域数据传输得以安全进行。(实现一个跨域请求的方式,其中html访问网址为http://127.0.0.1:8009; 服务器监听端口为:8010) 一、整体流程
CORS的通信流程是浏览器自动完成,不需要用户参与,其核心点是服务器,只要服务器实现了CORS接口就可以实现跨源通信了。虽然是浏览器自动完成,但是浏览器其实还是根据请求时字段的不同分为简单请求和非简单请求的,下面对这两者进行简要介绍。
简单请求 (1) 定义
只要满足以下两个条件就属于简单请求:
请求方法是一下三种方法之一:HEAD、GET、POST;
HTTP的头信息不超出以下几种字段:Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type(其值为application/x-www-form-urlencoded、multipart/form-data、text/plain三个中的一个)。
(2)流程
image-20210703182139849.png
简单请求的整个流程可以归结为以下步骤:
1) 浏览器直接发出CORS请求,具体来说就是在头信息之中增加一个Origin字段,该字段用来说明请求来自哪个源(协议+域名+端口),服务器根据这个值决定是否同意这次请求;2)当服务器接收到请求后,根据Origin判定指定的源是否在许可的范围内。3)如果不在许可范围内,服务器会返回一个正常的HTTP回应,浏览器发现该回应的头信息没有包含Access-Control-Allow-Origin字段,就知道出错了,从而抛出错误,被XML的onerror回调函数捕获。(注意:由于正常回应,其状态码为200,所以该错误不能通过状态码识别) 4)如果Origin指定的域名在许可范围内,服务器返回的响应中会多出几个头信息字段(Access-Control-Allow-Origin、Access-Control-Allow-Credentials、Access-Control-Expose-Header等)。
(3)关键字段
1) Access-Control-Allow-Origin
必须字段,该值要么是请求的Origin字段值,要么是一个*(表示接受任意域名的请求)。
2)Access-Control-Allow-Credentials
可选字段,其值是一个布尔值,表示是否允许发送Cookie。默认是不发送Cookie值,当设置为true时,表示服务器明确许可,Cookie可以包含在请求中发送给服务器。(注意:发送Cookie时要注意两点:一方面在Ajax请求中需要设置withCredentials属性;另一方面不能将Access-Control-Allow-Origin设置为*,需要指定明确的、与请求网页一致的域名)
3)Access-Control-Expose-Header
可选字段,当CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段(Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma),如果想获取其它字段必须在Access-Control-Expose-Header中指定。
非简单请求
(1)定义
不是简单请求的就是非简单请求,非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或Delete,或者Content-Type字段的类型是application/json.
(2)流程
image-20210703211106355.png
非简单请求相比于简单请求较复杂,在发起正式请求之前会进行一次预检请求,通过预检请求的结果来决定是否进行后续的正式通信。
1)浏览器发起预检请求,该请求的请求方法是options,该请求是用来询问的;2)服务器收到“预检”请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。3)如果浏览器否定了“预检”请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段,这时浏览器就会认定服务器不同意预检请求,触发错误;4)如果浏览器通过了“预检”请求,以后每次浏览器正常的CORS请求就跟简单请求一样,会有一个Origin头信息字段,服务器的回应也会有一个Access-Control-Allow-Origin头信息字段;
(3)关键字段
1)Access-Control-Request-Method
必须字段,用来列出浏览器的CORS请求会用到哪些HTTP方法。
2)Access-Control-Request-Headers
该字段是一个逗号分隔的字符串,用来指定浏览器CORS请求会额外发送的头信息字段。
3)Access-Control-Allow-Methods
必须字段,该值是一个逗号分隔的字符串,用来表明服务器支持的所有跨域请求的方法。
4)Access-Control-Allow-Headers
该值是一个逗号分隔的字符串,表明服务器支持的所有头信息字段。
5)Access-Control-Max-Age
用来请求预检请求的有效期,单位为秒。
简单实现
(1)html页面内容
test CORS
CORS
(2)服务器端代码
const express = require('express');
const app = express();
app.get('/', (req, res) => {
console.log('get请求收到了!!!');
res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:8009');
res.send('get请求已经被处理');
})
app.listen(8010, () => {
console.log('8010 is listening')
});
2.3.1 XSS
2.3.1.1 定义
跨站脚本攻击(XSS;Cross Site Scripting) 是指黑客往 HTML 文件中或者 DOM 中注入恶意脚本,从而在用户浏览页面时利用注入的恶意脚本对用户实施攻击的一种手段。
2.3.1.2 产生的影响
XSS攻击产生的影响主要有:盗取Cookie信息、监听用户行为、修改DOM、在页面内生成浮窗广告等。
image-20210801203139567.png
2.3.1.3 注入方式
XSS注入方式有存储型XSS攻击、反射型XSS攻击、基于DOM的XSS攻击。
image-20210801203233465.png
2.3.1.4 什么情况容易发生XSS攻击
容易发生XSS攻击的位置主要有两个:
数据从一个不可靠的链接进入到一个web应用程序
没有过滤掉恶意代码的动态内容被发送给Web用户
image-20210801203615476.png
2.3.1.5 如何阻止XSS攻击
阻止XSS攻击的方式主要有三种:
服务器对输入脚本进行过滤或转码;
充分利用CSP;
使用HttpOnly属性
image-20210801203703649.png
2.3.2 CSRF
2.3.2.1 定义
跨站请求伪造(CSRF;Cross-site request forgery)指的是黑客引诱用户打开黑客的网站,在黑客的网站中,利用用户的登录状态发起的跨站请求
2.3.2.2 产生影响
产生影响主要有以下几点:
image-20210801204412612.png
2.3.2.3 攻击原理
clipboard.png
2.3.2.4 攻击的前提条件
攻击的前提条件主要有以下三点:
image-20210801204503978.png
2.3.2.5 攻击方式
实施CSRF攻击的方式主要有以下三点:
2.3.2.6 防止CSRF攻击的策略
防止CSRF攻击的策略主要有以下三种:
充分利用好Cookie的SameSite属性;
在服务器端验证请求的来源站点;
CSRF Token。
image-20210801204552365.png
HTTP请求报文主要包括:请求行、请求头部以及请求的数据(实体),下面一起看看其组成内容:
3.1.1 请求行
请求行包含:方法字段、URI字段和协议版本
方法字段
GET(请求获取内容);
POST(提交表单);
HEAD(请求资源响应消息报头);
PUT(传输文件);
DELETE(请求删除URI指向的资源);
OPTIONS(查询针对请求URI指定的资源支持的方法);
TRACE(追踪请求经过路径);
CONNECT(要求用隧道协议连接代理)。
URI字段
协议版本
指的就是本次请求的HTTP协议版本,例如HTTP/0.9、HTTP/1.0、HTTP/1.1、HTTP/2.0、HTTP/3.0.
3.1.2 请求头部
常见标头有:Connection标头(连接管理)、Host标头(指定请求资源的主机)、Range标头(请求实体的字节范围)、User-Agent标头(包含发出请求的用户信息)、Accept标头(首选的媒体类型)、Accept-Language(首选的自然语言)
clipboard.png
3.1.3 请求实体
HTTP请求的body主要用于提交表单场景。实际上,http请求的body是比较自由的,只要浏览器端发送的body服务端认可就可以了。一些常见的body格式是:
application/json
application/x-www-form-urlencoded
multipart/form-data
text/xml
使用html的form标签提交产生的html请求,默认会产生 application/x-www-form-urlencoded 的数据格式,当有文件上传时,则会使用multipart/form-data。
HTTP响应报文分为三个部分:状态行、首部行和响应体.
3.2.1 状态行
状态行是由版本、状态码和原因语句组成,下面来看看一些常用的状态码。
1xx:这一类型的状态码,代表请求已被接受,需要继续处理。这类响应是临时响应,只包含状态行和某些可选的响应头信息,并以空行结束
2xx:这一类型的状态码,代表请求已成功被服务器接收、理解并接受
200---OK/请求已经正常处理完毕;
204---请求处理成功,但没有资源返回;
206---表示客户端进行了范围请求,而服务器成功执行了这部分的GET请求;
3xx:这类状态码代表需要客户端采取进一步的操作才能完成请求。通常,这些状态码用来重定向,后续的请求地址(重定向目标)在本次响应的Location域中指明
301---请求永久重定向 被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个 URI 之一。如果可能,拥有链接编辑功能的客户端应当自动把请求的地址修改为从服务器反馈回来的地址。
302---请求临时重定向 由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的。
303---表示由于请求对应的资源存在着另一个URI,应使用GET方法定向获取请求的资源
304---表示客户端发送附带条件的请求(指采用GET方法的请求报文中包含If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since中任一首部)时,服务端允许请求访问资源,但未满足条件的情况
307---临时重定向,与302含义相同,但是307会遵照浏览器标准,不会从POST变成GET
4xx:这类状态码代表客户端类的错误
400---客户端请求存在语法错误
401---当前请求需要用户验证。
403---服务器已经理解请求,但是拒绝执行它。与401响应不同的是,身份验证并不能提供任何帮助
404---请求失败,请求所希望得到的资源未被在服务器上发现。
405---请求行中指定的请求方法不能被用于请求相应的资源。
5xx:服务器类的错误
500---服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。
501---服务器不支持当前请求所需要的某个功能。当服务器无法识别请求的方法,并且无法支持其对任何资源的请求。
503---由于临时的服务器维护或者过载,服务器当前无法处理请求。
505---服务器不支持,或者拒绝支持在请求中使用的 HTTP 版本。
3.2.2 响应首部
常见的响应首部有:Date(响应的时间)、Via(报文经过的中间节点)、Last-Modified(上一次修改时间)、Etag(与此实体相关的实体标记)、Connection(连接状态)、Accept-Ranges(服务器可接收的范围类型)、Content-Type(资源类型)
clipboard.png
3.2.3 响应体
响应体就是响应的消息体,如果是纯数据就是返回纯数据,如果请求的是HTML页面,那么返回的就是HTML代码,如果是JS就是JS代码等。
正是由于HTTP存在一系列的缺点,所以才会出现HTTPS,那么HTTP存在哪些缺点呢?该如何解决的呢?下面来进行简要概述
1.HTTP通信使用明文(不加密),内容可能会被窃听;
TCP/IP是可能被窃听的网络:按TCP/IP协议族的工作机制,通信内容在所有线路上都有可能遭到窥视。所以需要加密处理防止被窃听,加密的对象如下:
(1)通信的加密
通过和SSL(Secure Socket Layer,安全套接层)或TLS(Transport Layer Security,安全层传输协议)的组合使用,加密HTTP的通信内容。用SSL建立安全通信线路之后,就可以在这条线路上进行HTTP通信了。与SSL组合使用的HTTP称为HTTPS,通过这种方式将整个通信线路加密。
(2)内容的加密
由于HTTP协议中没有加密机制,那么就对HTTP协议传输的内容本身加密。为了做到有效的内容加密,前提是要求客户端和服务器同时具备加密和解密机制。该方式不同于将整个通信线路加密处理,内容仍有被篡改的风险。
2.不验证通信方的身份,因此有可能遭遇伪装;
(1)任何人都可发起请求
HTTP协议不论是谁发送过来的请求都会返回响应,因此不确认通信方,会存在以下隐患:
1)无法确定请求发送至目标的Web服务器是否是按真是意图返回响应的那台服务器,有可能是已伪装的Web服务器;
2)无法确定响应返回到的客户端是否是按照真实意图接收响应的那个客户端,有可能是伪装的客户端;
3)无法确定正在通信的对方是否具备访问权限,因为某些Web服务器上保存着重要的信息,只想发给特定用户通信的权限;
4)无法判断请求是来自何方、出自谁手,即使是无意义的请求也会照单全收,无法阻止海量请求下的Dos攻击(Denial of Service,拒绝服务攻击)。
(2)查明对手的证书
SSL不仅提供加密处理,还使用了一种被称为证书的手段,可用于确定通信方。证书由值得信任的第三方机构颁发,用以证明服务器和客户端是实际存在的。使用证书,以证明通信方就是意料中的服务器,对使用者个人来讲,也减少了个人信息泄露的危险性。另外,客户端持有证书即可完成个人身份的确认,也可用于对Web网站的认证环节。
3.无法证明报文的完整性,所以有可能已遭遇篡改。
在请求或响应送出之后直到对方接收之前的这段时间内,即使请求或响应的内容遭到篡改,也没有办法获悉。在请求或响应的传输途中,遭攻击者拦截并篡改内容的攻击称为中间人攻击(Man-in-the-Middle attack)。仅靠HTTP确保完整性是非常困难的,便有赖于HTTPS来实现。SSL提供认证和加密处理及摘要功能。
HTTPS 并非是应用层的一种新协议。只是 HTTP 通信接口部分用SSL(Secure Socket Layer)和TLS(Transport Layer Security) 协议代替而已,简言之就是HTTP+通信加密+证书+完整性保护构成HTTPS,是身披TLS/SSL这层外壳的HTTP。
image-20210801193609652.png
TLS/SSL功能
TLS/SSL协议使用通信双方的客户证书以及CA根证书,允许客户/服务器应用以一种不能被偷听的方式通信,在通信双方间建立起了一条安全的、可信任的通信通道。
对称加密和非对称加密(公开密钥加密)
(1)对称加密
对称加密指的是加密数据用的密钥,跟解密数据用的密钥是一样的,使用该方法的优缺点是:
1)优点:加密、解密效率通常比较高、速度快。对称性加密通常在消息发送方需要加密大量数据时使用,算法公开、计算量小、加密速度快、加密效率高。
2)缺点:数据发送方、数据接收方需要协商、共享同一把密钥,并确保密钥不泄露给其他人。此外,对于多个有数据交换需求的个体,两两之间需要分配并维护一把密钥,这个带来的成本基本是不可接受的。
(2)非对称加密
非对称加密指的是加密数据用的密钥(公钥),跟解密数据用的密钥(私钥)是不一样的。公钥就是公开的密钥,谁都可以查到;私钥就是非公开的密钥,一般是由网站的管理员持有。公钥与私钥之间有一定联系:简单来说就是,通过公钥加密的数据,只能通过私钥解开;通过私钥加密的数据,只能通过公钥解开。
非对称加密(公开密钥加密)存在的问题
非对称加密其实是存在一些问题需要解决的,主要有以下两个:公钥如何获取、数据传输单向安全。
非对称加密中公钥如何获取
为了获取公钥,需要涉及到两个重要概念:证书、CA(证书颁发机构),其主要用途如下:
(1)证书:可以暂时把它理解为网站的身份证。这个身份证里包含了很多信息,其中就包含了上面提到的公钥。当访问相应网站时,他就会把证书发给浏览器;
(2)CA:用于颁发证书,证书来自于CA(证书颁发机构)。
证书可能存在的问题
(1)证书是伪造的:压根不是CA颁发的
(2)证书被篡改过:比如将XX网站的公钥给替换了
证书如何防伪
数字签名、摘要是证书防伪非常关键的武器。“摘要”就是对传输的内容,通过hash算法计算出一段固定长度的串。然后,在通过CA的私钥对这段摘要进行加密,加密后得到的结果就是“数字签名”(明文 --> hash运算 --> 摘要 --> 私钥加密 --> 数字签名);数字签名只有CA的公钥才能够解密。证书中包含了:颁发证书的机构的名字 (CA)、证书内容本身的数字签名(用CA私钥加密)、证书持有者的公钥、证书签名用到的hash算法等。
(1)对于完全伪造的证书
这种情况对证书进行检查
1)证书颁发的机构是伪造的:浏览器不认识,直接认为是危险证书
2)证书颁发的机构是确实存在的,于是根据CA名,找到对应内置的CA根证书、CA的公钥。用CA的公钥,对伪造的证书的摘要进行解密,发现解不了。认为是危险证书
(2)篡改过的证书
1)检查证书,根据CA名,找到对应的CA根证书,以及CA的公钥。
2)用CA的公钥,对证书的数字签名进行解密,得到对应的证书摘要AA
3)根据证书签名使用的hash算法,计算出当前证书的摘要BB
4)对比AA跟BB,发现不一致--> 判定是危险证书
HTTPS问题
(1)与纯文本相比,加密通信会消耗更多的CPU及内存资源
1)由于HTTPS还需要做服务器、客户端双方加密及解密处理,因此会消耗CPU和内存等硬件资源。
2)和HTTP通信相比,SSL通信部分消耗网络资源,而SSL通信部分,由因为要对通信进行处理,所以时间上又延长了。SSL慢分两种,一种是指通信慢;另一种是指由于大量消耗CPU及内存等资源,导致处理速度变慢。
(2)购买证书需要开销。
1.客户端发起HTTPS请求
2.服务端响应,下发证书(公开密钥证书)
3.客户端检查证书,如果证书没问题,那么就生成一个随机值,然后用证书(公钥)对该随机值进行加密。
4.将经过公钥加密的随机值发送到服务端(非对称加密),以后客户端和服务器的通信就可以通过这个随机值进行加密解密了。
5.服务端用私钥解密后,得到了客户端传过来的随机值,然后把内容通过该值进行对称加密。
6.后期的数据传输都是基于该随机值进行加密解密。
img
注:图片来源于(https://blog.csdn.net/qq_33840251/article/details/91358884)
浏览器工作原理与实践_李兵
阮一峰 跨域资源共享 CORS 详解