前言
《图解HTTP》中这样描述HTTP在网络中的地位
Web使用一种名为HTTP(HyperText Transfer Protocol,超文本传输协议)的协议作为规范,完成从客户端到服务器等一系列运作流程。而协议是指规则的约定。可以说,Web是建立在HTTP协议上通信的。
HTTP是不保存状态的协议,即无状态协议,协议本身对于请求或响应之间的通信状态不进行保存,因此连接双方并不知道对方当前的身份和状态。这也是Cookie技术产生的重要原因之一:客户端的状态管理。每次客户端发送HTTP请求,都会在请求报文中携带Cookie,作为服务端识别客户端身份状态的标识。
HTTP的版本演变
HTTP/1.1
HTTP最早在网页中使用时1996年,那个时候只是使用一些较为简单的网络请求,随着互联网的发展在1999年开始广泛使用更为优化的HTTP/1.1。主要特点有:
-
采用长连接:
相较于HTTP/1.0的短连接(也被称为串行连接、短轮询)中每次HTTP通信后都要断开TCP连接,造成很大的通信开销。HTTP/1.1采用了只要双方没有提出断开连接就会持久保持TCP连接状态的长连接。这样客户端发起多个HTTP请求时就会减少TCP握手造成的网络资源和通信时间的浪费。但是长连接会造成队头阻塞(Head-Of-LIne Blocking)造成带宽无法呗充分利用。队头阻塞是指当顺序发送请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求一并被阻塞。
-
Host头处理:
随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且他们共享一个IP地址。HTTP/1.1请求消息和响应消息包含Host头部,以区分一个物理主机中的不同虚拟主机的域名。
-
引入缓存控制策略:
Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。
-
明文传输:
HTTP/1.1在传输数据时,所有传输的内容都是明文,客户端和服务器端都无法验证对方身份,这在一定程度上无法保证数据的安全性。
HTTP/2
2015年,HTTP/2 发布。HTTP/2是现行HTTP协议(HTTP/1.x)的替代,但它由不是重写,HTTP方法/状态码/语义都与HTTP/1.x一样。HTTP/2基于SPDY,专注于性能,最大的目标是在用户和网站之间只用一个连接。目前看来排名靠前的站点基本都实现了HTTP/2的部署。
在HTTP/2中,有两个非常重要的概念,分别是帧(frame)和流(steam),理解这两个概念是理解HTTP/2重要特点--多路复用的前提。帧代表数据传输的最小单位,每个帧都有序列标识表明该帧数语哪个流。流就是多个帧组成的数据流,每个数据流表示一个请求。
HTTP/2主要特点有:
-
二进制传输:
HTTP/2的传输数据量大幅减少,主要有两个原因:以二进制传输和Header压缩。HTTP/2采用二进制格式进行传输数据,而非HTTP/1.x里纯文本形式的报文,二进制协议解析起来更加高效。
-
头部压缩:
HTTP/1.x的请求和响应头部带有大量信息,而且每次请求都需要重复发送 ,用encoder来减少需要传输的头部大小,通讯双方各自cache一份头部fields表,避免头部重复发送。
-
多路复用:
多路复用就是在一个TCP连接中存在多条流,通过重新排序还原请求。多路复用允许并发的发送多个请求,每个请求及该请求的响应不需要等待其他请求或响应,有效避免了队头阻塞问题。这样,某个任务请求耗时严重,不会影响到其他连接的正常执行。多路复用并不是完美避免队头阻塞问题。
这是因为,TCP有特别的丢包重传的机制,一旦HTTP/2出现丢包,丢失的包必须要等待重新传输确认,整个TCP连接都要开始等待重传,那么就会阻塞该TCP连接中的所有请求。这种情况下反而比HTTP/1.1延迟更高,因为HTTP/1.1是采用多个长连接进行通讯。
如上图所示,多路复用只通过一个TCP连接传输所有的请求数据。
-
服务端推送(Server Push):
HTTP/2 一定程度上改变了服务端传统的“请求-应答”工作模式,服务端不再是完全被动的响应请求。如,把浏览器刚请求的HTML时候提前把可能会用到的
JS、CSS
等文件发给客户端,减少等待延迟。当然,客户端是有权力选择是否接收,如果发现客户端已经缓存了,那客户端就会发送RST_STREAM
帧来拒收。 -
安全性提升:
出于兼容考虑,HTTP/2依旧采用明文特点,不强制使用加密。
但由于HTTPS已经是大势所趋,主流的浏览器
Chrome、Firefox
都公开宣布只支持加密的HTTP/2。所以通常来说HTTP/2都是使用“https”协议名,跑在TLS上面。
HTTP/3
Google在推出SPDY(就是HTTP/2基于的协议)的时候意识到了SPDY的问题是底层支撑的TCP协议造成的。主要有以下缺点:
-
TCP以及TCP+TLS建立连接的延时:
在建立TCP连接时,需要与服务器进行三次握手进行确认连接,需要消耗1.5个RTT。
HTTP/2还需要与TLS进行连接,大致需要1~2个RTT
所以总的来说在传输数据前我们就得花掉3~4个RTT
-
TCP的队头阻塞并没有解决:
前面我们提到不论是HTTP/1.x还是HTTP/2都并没有完美解决队头阻塞问题。
这样看来TCP才是最大的问题,所以就想到了另起炉灶。
Goole推出了基于UDP协议的QUIC协议,让HTTP跑在QUIC上,而不是TCP上。HTTP over QUIC就是HTTP协议的下一个大版本,它在HTTP/2的基础上又实现了质的飞跃,完美的解决了队头阻塞。
以下是HTTP/3的一些特点:
-
实现了类似TCP的流量控制、传输可靠性的功能:
虽然UDP不提供可靠性传输。但它提供了数据包重传、拥塞控制以及其他一些TCP的特性。
-
实现了快速握手功能:
由于底层协议是UDP,所以可以实现0-RTT或者1-RTT来建立连接,大大提升了速度。
-
集成TLS加密功能:
使用的TLS1.3,减少了所花费的RTT。
-
多路复用:
实现了同一个物理连接上可以有多个独立逻辑的数据流,实现了数据流的单独传输,解决了TCP中的队头阻塞问题。
HTTP报文
用于HTTP协议交互的信息被称为HTTP报文。客户端的HTTP报文叫做请求报文,服务端的HTTP报文叫做响应报文。
请求报文是由:请求行(请求方法、协议版本)、请求首部(请求URI、客户端信息等)、内容实体(用户信息和资源信息等)
响应报文是由:状态行(状态码、协议版本)、响应首部(服务器名称、资源标识等)、内容实体(服务端返回的资源信息等)
请求方法
方法 | 说明 |
---|---|
GET | GET请求会显示请求指定的资源。一般来说GET方法应该只用于数据的读取,而不应当用于会产生副作用的非幂等的操作中。它期望的应该是而且应该是安全的和幂等的。这里的安全指的是,请求不会影响到资源的状态。 |
POST | POST请求会 向指定资源提交数据,请求服务器进行处理,如:表单数据提交、文件上传等,请求数据会被包含在请求体中。POST方法是非幂等的方法,因为这个请求可能会创建新的资源或/和修改现有资源。 |
HEAD | HEAD方法与GET方法一样,都是向服务器发出指定资源的请求。但是,服务器在响应HEAD请求时不会回传资源的内容部分,即:响应主体。这样,我们可以不传输全部内容的情况下,就可以获取服务器的响应头信息。HEAD方法常被用于客户端查看服务器的性能。 |
PUT | PUT请求会身向指定资源位置上传其最新内容,PUT方法是幂等的方法。通过该方法客户端可以将指定资源的最新数据传送给服务器取代指定的资源的内容。 |
DELETE | DELETE请求用于请求服务器删除所请求URI(统一资源标识符,Uniform Resource Identifier)所标识的资源。DELETE请求后指定资源会被删除,DELETE方法也是幂等的。 |
OPTIONS | OPTIONS请求与HEAD类似,一般也是用于客户端查看服务器的性能。 这个方法会请求服务器返回该资源所支持的所有HTTP请求方法,该方法会用'*'来代替资源名称,向服务器发送OPTIONS请求,可以测试服务器功能是否正常。JavaScript的XMLHttpRequest对象进行CORS跨域资源共享时,就是使用OPTIONS方法发送嗅探请求,以判断是否有对指定资源的访问权限。 |
POST与GET的区别
-
本质区别:
本质上他们只是幂等和非幂等的区别
-
使用区别:
- GET使用URL,而POST使用body进行传值。这主要是因为浏览器直接发出GET请求,只能由一个URL触发。
- GET传值有长度限制,POST传值并没有长度限制。这主要是因为浏览器对URL有着长度限制,而并非GET和POST的区别
- POST相较于GET更加安全,因为URL在地址栏是可见的。但如果是使用HTTP作为底层协议,他们都是不安全的。
-
什么是幂等?
从定义上看,HTTP方法中的幂等性是指:一次或多次请求某一个资源应当具有相同的副作用。
状态码
HTTP状态码是用以表示Web服务器HTTP响应状态的3位数字代码。
1XX | 表示继续发送请求 |
---|---|
100(Continue) | 客户端应继续发送请求 |
101(Switching Protocols) | 需要切换协议 |
2xx | 请求已成功被服务器接收、理解并接受 |
---|---|
200(OK) | 请求已成功,请求所希望的响应头或数据提将随此响应返回 |
201(Accepted) | 请求已经被实现,而且有一个新的资源已经依据请求的需要而创建。 |
202(Accpted) | 服务器已经接受请求,但尚未处理。比如post一个资源应当返回201,但由于性能原因未能立即创建,可以返回202 |
203(No Content) | 服务器成功处理请求,但不需要返回任何实体内容且不产生文档视图变化 |
205(Reset Content) | 服务器成功处理里请求,但不需要返回任何实体内容,与204区别是会重置文档视图 |
206(Partial Content) | HTTP协议允许分片传输。 |
3XX | 代表客户端需要采取进一步的操作才能完成请求 |
---|---|
300(Multiple Choices) | 客户端请求实际指向多个资源的URL会返回这个状态码。比如说网站的中英文切换,300属于客户端驱动由客户端发起请求,服务器发送可选项的列表,服务端返回300,可能弹出对话框让用户选择。 |
301(Moved Permanently) | 被请求的资源已经被永久的移动到新的位置,并且将来任何对此资源的引用都应使用本响应返回的URI |
302(Found) | 与301状态码类似,但是客户端应该使用Location首部给出URL来临时定位资源,将来的请求仍应使用旧的URL |
303(See Other) | 用来告知客户端应该使用另一个URL来获取资源 |
304(Not modified) | 表示服务器允许访问资源,但文档的内容(自上次访问以来或者根据请求的条件)并没有改变。 |
4xx | 客户端错误 |
---|---|
400(Bad Request) | 请求报文中存在语法错误 |
401(Unauthorized) | 当前请求需要用户验证,响应中会包含WWW-Authenticate 字段来询问用户的授权消息,而客户端下次请求需要提供包含Authorization 头的请求 |
403(Forbidden) | 表示请求资源的访问被服务器拒绝,直接返回当前错误 |
404(Not Found) | 请求得到的资源未在服务器上被发现 |
5xx | 这类状态码代表了服务器在处理请求的过程中有错误或有异常状态发生 |
---|---|
500(Intenrnal Server Error) | 代码出错 |
501(Not Implemented) | 表示服务器不支持当前请求所需要的某个功能 |
503(Service Unavailable) | 表明服务器出于超载或正在停机维护 |
504(Gateway Time-out) | 响应超时,通常被墙了 |
首部字段
通用首部 | 作用(请求报文和响应报文都可能使用) |
---|---|
Cache-control | 控制缓存的行为:no-cache (强制向服务器再次验证)、no-store (不做任何缓存)、max-age=1111 (资源可缓存最大时间)、public (客户端、服务器都可以利用缓存)、private (代理服务器不可用缓存) |
Connection | 请求:close(告诉WEB服务器或者代理服务器,在完成本次请求的响应后,断开连接,不要等待本次连接的后续请求了)。 keepalive(告诉WEB服务器或者代理服务器,在完成本次请求的响应后,保持连接,等待本次连接的后续请求)。 响应:close(连接已经关闭)。 keepalive(连接保持着,在等待本次连接的后续请求)。 |
Date | 创建报文时间 |
via | 代理服务器的相关信息,每经过一个代理服务器就会添加相关信息 |
Transfe-Encoding | 传输编码方式 |
Upgrade | 要求客户端使用的升级协议,需配合Connection:Upgrade 一起使用 |
Warning | 缓存问题相关警告 |
请求首部 | 作用(请求报文专用) |
---|---|
Accept | 能正确接收的媒体类型:application/json 、text/plain |
Accept-Charset | 能正确接收的字符集 |
Accept-Encoding | 能正确接收的编码格式列表 |
Accepte-Language | 能正确接收的语言列表 |
Authorization | 客户端认证信息,当客户端接收到来自WEB服务器的 WWW-Authenticate 响应时,用该头部来回应自己的身份验证信息给WEB服务器 |
Host | 客户端指定自己想访问的WEB服务器的域名/IP 地址和端口号。 |
If-Match | 如果对象的 ETag 没有改变,其实也就意味著对象没有改变,才执行请求的动作。 |
If-Modified-Since | 如果请求的对象在该指定的时间之后修改了,才执行的请求动作,否则返回304 |
User-Agent | 浏览器表明自己的身份 |
响应首部 | 作用(响应报文专用) |
---|---|
Age | 告知客户端 |
Etag | 资源标识,资源发生变化时标识也会发生变化 |
Location | 服务器告诉浏览器,试图访问的对象已经被移到别的位置上了 |
Server | 服务器表明自己是什么软件及版本信息 |
proxy-Authenticate | 代理服务器响应浏览器,要求其提供代理身份验证信息 |
实体首部 | 作用(补充请求报文或响应报文相关信息) |
---|---|
Allow | 资源正确的请求方式:GET 、POST 、HEAD |
Content-Encoding | 内容使用的编码格式 |
Content-Language | 内容使用的语言 |
Content-Length | 实体主体的长度 |
Content-Loaction | 返回数据的备用地址 |
Content-MD5 | Base64加密格式的内容MD5检验值 |
Web服务器
虚拟主机
HTTP/1.1规范允许一台HTTP服务器搭建多个Web站点。利用虚拟主机的功能,可以在一台服务器上虚拟出多个主机,每个主机映射一个独立域名。因此,当用户访问域名时,DNS域名系统会解析成IP地址,根据IP找到物理服务器,然后再通过首部的HOST字段找到相应的虚拟主机
代理服务器
代理服务器就是客户端和服务端之间的“中间商”,就是HTTP请求通过代理服务器转发给服务器,再将服务器的响应返回给客户端行为。代理服务器用来作为缓存服务器,也可以用来隐藏用户身份。
- 正向代理:正向代理是从客户端角度出发,为了从源服务器取得内容,由客户端向代理服务器发出请求,并指定目标访问服务器,代理服务器向源服务器转交需求,并将获得的内容返回给客户端。正向代理隐藏了真实请求的客户端,即服务端并不知道正式请求的是谁。
- 反向代理:反向代理是客户端向反向代理代理服务器发出请求,反向代理服务器收到需求后判断请求走向何处,然后再将响应返回给客户端。反向代理隐藏了内部服务器的信息,用户不需要知道具体哪一台服务器提供服务,只要知道反向代理服务器是谁就好。反向代理通常被用作实现负载均衡。
HTTPS
什么是HTTPS
超文本传输安全协议(英语:Hypertext Transfer Protocol Secure,缩写:HTTPS,常称为HTTP over TLS,HTTP over SSL或HTTP Secure)是一种通过计算机网络进行安全通信的传输协议。HTTPS经由HTTP进行通信,但利用SSL/TLS来加密数据包。HTTPS开发的主要目的,是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。
为什么需要HTTPS
HTTP本身是明文传输,这就造成了很大的安全问题,为了解决安全问题,推出了HTTPS。HTTPS是在通信接口用TLS(Transport Layer Security 传输层安全性协议),用于两个应用程序间通过网络创建起安全的连接,防止在交换数据时收到窃听以及篡改。
- HTTP存在的问题:
- 通信使用明文(不加密),内容可能被窃听
- 无法证明报文的完整性,所以可能被篡改
- 不验证通信方的身份,因此有可能遭遇篡改
- HTTPS协议相比HTTP的优势
- 数据隐私:内容经过对称加密,每个连接生成唯一的加密密钥
- 数据完整性:内容传输经过完整性校验
- 身份认证:第三方无法伪造服务端
HTTPS解决内容可能被窃听--加密
HTTPS协议的主要功能都依赖于TLS/SSL协议,TLS/SSL协议的功能是心啊主要依赖于三类基本算法:散列函数、对称加密、非对称加密,利用非对称加密实现身份的认证和密钥协商,而数据通信则协商的对称机密进行加密,然后基于散列函数验证信息的完整性。
-
对称加密:
这种方式加密以及解密同用一个密钥。加密和解密都需要用到密钥,没有密钥就无法解密。反过来讲,只要谁持有密钥都能进行解密。
以对称加密的方式必须将密钥发送给对方,可是怎样才能安全的发送给对方呢?互联网发送很有可能被劫持,这就失去了加密的意义。
-
非对称加密:
这种加密方式会有两把密钥,一把私有密钥由服务端保存起来,不让任何人知道。而公开密钥则可以随意发布,任何人都可以获得。
使用公开密钥加密,发送密文的一方使用对方公开的公钥进行加密处理,对方收到由公钥加密的信息后,使用自己的私钥进行解密。使用这种方式,即使信息被劫持也无法得到里面的信息(就像一个上了锁的保险箱)
但非对称加密中公钥并不包含服务器信息,使用非对称加密算法无法确保服务器身份的合法性,存在中间人攻击的风险。同时非对称加密过程也需要消耗一定的时间,降低数据传输效率
-
混合加密(对称加密+非对称加密 HTTPS使用这种方式)
对称加密好处是解密效率快,非对称加密是可以使得内容不被破解,两者各有优缺点,将他们结合起来就会更大的发挥他们的优势隐藏他们的缺点。
具体为:发送密文的一方使用服务端发送过来的公钥进行加密处理对称密钥,然后服务端用自己的私钥解密拿到对称密钥,这样可以确保交换的密钥是安全的前提下,使用对称加密的方式进行通信。
HTTPS解决身份伪装问题
为了让客户端能够验证公钥的来源,我们给公钥加上一个数字签名,这个数字签名是由企业、网站等各种信息和公钥经过单向hash而来,一旦构成数字签名的信息发生变化,hash值就会改变,这就构成了公钥来源的唯一标识。
具体来说,服务端本地生成一对密钥,然后拿着公钥以及企业、网站等各种信息到CA(第三方认证中心)去申请数字证书,CA会通过一种单向hash算法(比如MD5),生成一串摘要,这串摘要就是这堆信息的唯一标识,然后CA还会使用自己的私钥对摘要进行加密,连同我们自己服务器的公钥一同发送给我我们。
浏览器拿到数字签名后,会使用浏览器本地内置的CA公钥解开数字证书并验证,从而拿到正确的公钥。由于非对称加密性能低下,拿到公钥以后,客户端会随机生成一个对称密钥,使用这个公钥加密并发送给服务端,服务端用自己的私钥解开对称密钥,此后的加密连接就通过这个对称密钥进行对称加密。
总结:HTTPS的工作流程
- Client发起了一个HTTPS的请求,根据RFC2818的规定,Client知道需要连接Server的443(默认)端口。
- Server把事先配置好的公钥证书(Public key certificate)返回给客户端
- Client验证公钥证书:比如是否在有效期内,证书的用途是否匹配Client请求的站点,是不是在CRL吊销列表中,它的上一级证书是否有效,这是一个递归过程,直到验证到根证书(操作系统内置的Root证书或者Client内置的Root证书)。如果验证通过则继续,不通过则显示警告信息。
- Client使用伪随机数生成加密使用的对称密钥,然后用证书加密这个对称密钥,发给Server
- Server使用自己的私钥解密这个消息,得到对称密钥。至此Client与Server双方都持有相同的对称密钥。
- Server使用对称密钥加密“内容”,发送给Client
- Client使用对称密钥解密相应的密文,得到“内容”
HTTP与HTTPS的区别
-
HTTPS比HTTP更加安全,对搜索引擎更友好,利于SEO,谷歌、百度优先搜索HTTPS的网页
-
HTTP协议运行在TCP之上,所有传输的内容都是明文,HTTPS运行在SSL/TLS之上,SSL/TLS运行在TCP之上,所有传输的内容都经过加密的。
-
HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
-
http的连接很简单,是无状态的;HTTPS协议是由HTTP+SSL协议构建的可进行加密传输、身份认证的网络协议,可以有效的防止运营商劫持,解决了防劫持的一个大问题,比http协议安全
Web安全
XSS攻击
什么是XSS
Cross-Site Scripting(跨站脚本攻击)简称XSS,是一种代码注入攻击。攻击者通过在目标网站上注入恶意脚本,使之在用户浏览器上运行。利用这些恶意脚本,攻击者可以获得用户的敏感信息如Cookie、SessionID等,进而危害数据安全。
XSS的本质是:恶意代码未经过过滤,与网站正常的代码混在一起,浏览器无法分辨哪些脚本是可信的。导致恶意脚本被执行。
一些用户的UGC内容都可以进行注入,所以以下内容均不可信:
- 来自用户的UGC内容
- 来自第三方的链接
- URL参数
- POST参数
- Referer(可能来自不可信的来源)
- Cookie(可能来自子域注入)
XSS攻击详述
根据攻击来源,可以将XSS攻击分为存储型、反射型、DOM型
存储型XSS
存储型XSS攻击步骤:
-
攻击者将恶意代码提交到目标网站的数据库中。
-
用户打开目标网站时,网站服务端将恶意代码从数据库取出,拼接在HTML中返回给浏览器
-
用户浏览器收到响应后解析执行,混在其中的恶意代码也被执行
-
恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户行为,调用目标网站接口执行攻击者指定的操作
常用于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信
反射型XSS
反射型XSS的攻击步骤:
- 攻击者构造出特殊的URL,其中包含恶意代码。
- 用户打开恶意代码的URL,网站服务器从URL中取出,拼接在HTML返回给浏览器
- 用户浏览器接收到恶意代码后解析执行,混在其中的恶意代码也被执行
- 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户行为,调用目标网站接口执行攻击者指定的操作
由于需要用户主动打开恶意的URL才能生效,攻击者往往结合多种手段诱导用户点击
DOM型XSS
DOM型XSS攻击的步骤:
- 攻击者构造出特殊的 URL,其中包含恶意代码。
- 用户打开带有恶意代码的 URL。
- 用户浏览器接收到响应后解析执行,前端 JavaScript 取出 URL 中的恶意代码并执行。
- 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
DOM型XSS与前两种XSS的区别:DOM型取出和执行恶意代码由浏览器端执行,属于前端的安全漏洞,而其他两种都属于服务端的安全漏洞。
XSS攻击的预防
预防存储型和反射型的XSS攻击
- 利用 HttpOnly
很多 XSS 攻击脚本都是用来窃取Cookie, 而设置 Cookie 的 HttpOnly 属性后,JavaScript 便无法读取 Cookie 的值。这样也能很好的防范 XSS 攻击。
- 对HTML做充分的转义
需要采用合适的转义库,因为HTML的编码是十分的复杂,需要在不同的上下文要使用相应的转义规则
预防DOM型XSS攻击
DOM型XSS攻击,实际上是网站前端JavaScript代码本身不够严谨,把不可信的数据作为代码执行。
在使用 .innerHTML
、.outerHTML
、document.write()
时要特别小心,不要把不可信的数据作为 HTML 插到页面上,而应尽量使用 .textContent
、.setAttribute()
等。
避免字符串中拼接不可信的数据
CSRF攻击
什么是CSRF
CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击的网站发送跨站请求。利用受害者在被攻击网站已获取的注册凭证,绕过后台的用户验证,达到冒充用户被攻击的网站进行某项操作的目的。
CSRF攻击的流程
- 受害者登陆站点A,并保留了登陆凭证
- 攻击者诱导受害者访问了站点B
- 站点B向站点A发送了请求,浏览器会默认携带站点A的Cookie的信息
- 站点A收到请求,验证出是受害者的凭证,便回应了站点B的请求
- 攻击完成,站点B在受害者不知情的情况下,冒充受害者完成了攻击
CSRF的预防
同源检测
在HTTP协议中,每一个异步请求都会携带两个Header ,用来标记来源域名,分别是Origin Header
、Referer Header
。这两个Header在请求时,大多数是会自动带上,并且不能由前端自定义内容,服务器可以解析这两个Header中的域名,确定请求的来源域。
-
Origin Header
在部分与CSRF有关的请求中,请求的Header中会携带Origin字段,字段内包含请求的域名。但部分情况Origin并不存在:
-
IE11同源策略:
由于IE11的同源策略不同,不会在跨站的CORS请求上添加Origin标头,Referer头将是唯一标识。
-
302重定向:
在302重定向后,Origin不包含在重定向的请求中,因为302是临时重定向,浏览器不会将Origin泄漏给新服务器。
-
-
Referer Header
根据HTTP协议,在HTTP头中有一个字段叫做Referer,记录了该HTTP请求的来源地址。但由于每个浏览器的对Referer的具体实现不同,并且攻击者是可以隐藏甚至修改自己请求的Referer。
CSRF Token
但用户打开页面的时候,服务器会给这个用户生成一个Token
,该Token通过加密算法对数据进行加密,一般Token都包括字符串和时间戳的组合。由于CSRF攻击就是冒用用户的Cokkie,所以我们不能再将Token放在Cookie中,为了安全起见我们可以把Token放在服务器Session
中,之后每次页面加载时,遍历DOM树将其中所有a
和form
加入Token。但对于动态生成的HTML
,这种方法就没用。
增加验证码和密码
验证码可以很好的防御住CSRF攻击,但我们不能多次添加验证码和密码,这样对用户的体验是很不好的。但是我们在转账、交易等操作,添加密码输入、验证码可以确保我们账户安全。
双重Cookie
利用CSRF攻击不能获取到用户的Cookie的特点,我们可以要求Ajax和表单请求携带一个Cookie中的值。
- 在用户访问网站页面时,向请求域注入一个Cookie,内容为随机字符
- 在前端向后端发送请求时,取出Cookie,并添加到URL的参数中。
- 后端接口验证Cookie中的字段和URL参数中的字段是否一样
Samesite Cookie 属性
为了从源头解决CSRF问题,Google起草了一份草案来改进HTTP协议,那就是为Set-Cookie响应头添加Samesite属性,用来标明是否为同站Cookie。
-
Samesite=Strict
严格模式,表明这个Cookie在任何情况下都不可能作为第三方Cookie,绝无例外。比如说我们从百度搜索的页面的链接进入淘宝后,在严格模式下都不会是登录状态,因为淘宝不会接受这个Cookie。
-
Samesite=Lax
宽松模式,这个模式下不同网站通过链接跳转是不受影响的,会发送Cookie,但假如是异步操作或者是页面跳转是通过表单的POST提交触发的则也不会发送Cookie。
但目前来说SamesiteCookie兼容性并不好,Safari并不支持。并且SamesiteCookie并不支持子域。例如:在topic.a.com下的Cookie并不支持使用a.com下设置的samesiteCookie。