超文本传输协议(英语:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议[1]。HTTP是万维网的数据通信的基础。
设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。通过HTTP或者HTTPS协议请求的资源由统一资源标识符(Uniform Resource Identifiers,URI)来标识。
HTTP的发展是由蒂姆·伯纳斯-李于1989年在欧洲核子研究组织(CERN)所发起。HTTP的标准制定由万维网协会(World Wide Web Consortium,W3C)和互联网工程任务组(Internet Engineering Task Force,IETF)进行协调,最终发布了一系列的RFC,其中最著名的是1999年6月公布的 RFC 2616,定义了HTTP协议中现今广泛使用的一个版本——HTTP 1.1。
2014年12月,互联网工程任务组(IETF)的Hypertext Transfer Protocol Bis(httpbis)工作小组将HTTP/2标准提议递交至IESG进行讨论[2],于2015年2月17日被批准。[3] HTTP/2标准于2015年5月以RFC 7540正式发表,取代HTTP 1.1成为HTTP的实现标准。[4]
浏览器访问Web服务
HTTP协议是构建在TCP/IP协议之上的,是TCP/IP协议的一个子集。
TCP/IP协议族是一个由四层协议组成的系统:应用层、传输层、网络层和链路层。
应用层:一般是我们编写的应用程序,决定了向用户提供的应用服务。应用层可以通过系统调用与传输层进行通信。
传输层:传输层通过系统调用。向应用层提供处于网络连接中的两台计算机之间的数据传输功能。TCP/UDP。
网络层:网络层用来处理在网络上流动的数据包,数据包是网络传输的最小数据单位。规定了通过怎样的路径(传输路线)到达对方计算机,并发数据包传输给对方。
链路层:处理连接网络的硬件。
数据包封装过程
TCP三次握手
第一次握手:客户端发送带有SYN标志的连接请求报文,然后进入SYN_SEND状态,等待服务端的确认。
第二次握手:服务端接收到客户端的SYN报文段后,需要发送ACK信息对这个SYN报文段进行确认。同时,还要发送自己的SYN请求信息。服务端会将上述的信息放到一个报文段(SYN+ACK报文段)中,一并发送给客户端,此时服务端将会进入SYN_RECV状态。
第三次握手:客户端接收到服务端的SYN+ACK报文段后,会向服务端发送ACK确认报文段,这个报文段发送完毕后,客户端和服务端都进入ESTABLISHED状态,完成三次握手。
DNS服务提供域名到IP地址之间的解析服务。
DNS请求优先级:
我们以一次抓包为例,体会下。
统一资源标识符(英语:Uniform Resource Identifier,缩写:URI)在电脑术语中是一个用于标识某一互联网资源名称的字符串。
该种标识允许用户对网络中(一般指万维网)的资源通过特定的协议进行交互操作。URI的最常见的形式是统一资源定位符(URL),经常指定为非正式的网址。更罕见的用法是统一资源名称(URN),其目的是通过提供一种途径。用于在特定的名字空间资源的标识,以补充网址。
统一资源定位符(英语:Uniform Resource Locator,缩写:URL;或称统一资源定位器、定位地址、URL地址[1],俗称网页地址或简称网址)是因特网上标准的资源的地址(Address),如同在网络上的门牌。它最初是由蒂姆·伯纳斯-李发明用来作为万维网的地址,现在它已经被万维网联盟编制为因特网标准RFC 1738。
在互联网的历史上,统一资源定位符的发明是一个非常基础的步骤。统一资源定位符的语法是一般的,可扩展的,它使用美国信息交换标准代码的一部分来表示因特网的地址。统一资源定位符的开始,一般会标志着一个计算机网络所使用的网络协议。
统一资源名称(英语:Uniform Resource Name,缩写:URN)是统一资源标识(URI)的历史名字,它使用
urn:
作为URI scheme。1997年的RFC 2141定义了URN,期望为资源提供持久的、位置无关的标识方式,并允许简单地将多个命名空间映射到单个URN命名空间。这样一个URI的存在并不意味着被标识的资源一定是可用的,但它仍然需要保持全局唯一和持久,即使资源已经不存在了或变得不可用。[1]
POST /wpsv6internet/infos.ads?v=D1S1E2 HTTP/1.1
Content-Length: 1086
Connection: Keep-Alive
Accept-Encoding: gzip
Accept-Language: zh-CN,en,*
User-Agent: Mozilla/5.0
Host: ic.wps.cn
Content-Type: application/x-www-form-urlencoded
hPNFo0JCs0JCnCJ3ACdRz07Dy1tDy17EDemShrJGH9sCCjMDhPqBYDNOa1bPrjILebrQZbqTMjYDsWrLhOsBB1ZDHTpHZ9sHqCcJla4IfLLDLbdJ71ZIcb5LricMqzqTFbbHpaMDETMJtKcIdvKCNvcCherApjcSLL3SpjKKA1bQliISXPMQHz6TtDJD4vcIXPqI556Hti4Eru6KaT7CQDNQvjoLqyIHl9dTn9qSDTrQ4P6Md5sHezoR7fbRlH7R7zKM2HqDqeLG6PNUZ1tIO9MRODdGsOdTLDMHqWKOInaJr4qJBT3DHHNS6ftKhv4TGX4Uf5pKvSaPnLNSt1rOsvMQgnKUl0tJwXsCgXNJ8bNJaPdI5HrCA57DAnqSmLpTIP6L6bbDO5tHli4Qev4Sb93C7PNCnmqDpCNQn1bK75NCoXNGNDKSaLKSknaTKHZHEbsSr4MHLr6I8PdJmrqAYn6D5DMKLPdO5LtSfjoSsPdHQTNFzqW2arMFlS7SpzoOibMPkHtBmnMTdbcRprW2XD6TfzcRzqsSdz5To5sObHJ3A07CzCaH4PKC6TpD5HKDoGJCpKZG1bJHsOZDsGJCrC3DnKJHyLJOnW3Pva3DZ1pCtCsOvGZCuGZDZDZDq4JCqW3PrCpOyHcPsKJCp03DY1pDYP6Pu0ZCt83PnKpDZ5ZDXXpDm8MCDe0SnqJCnuoCk0ZBuSpDrqW2m9JFm03Cp0ZBm03Cm43CmGJ3A0tCz4ZBmuYDkaJ3A07DzGrRqXZOMvaGtSbT85dSj9rP2TsQq5qBKT6RPH4LGbNCBrsTqHaONHJTkbLFDe0SrqJCDe0SsqJ3A0tDz4qOhycOfX6T2bJC3DNKKH7Di5NJl1LO7XJOjH4EvOZPvTKLmScJeX4LfDNFDe0SuqJGZjoRYb6Qq9KEnCqSHH5TqmMSDzMIv15EHn6IsS6QD5aUJrMKq13QY9dTIvMSF9KU3H6MFjcPu03M653RonaUv8tKKrqDdLbKsaZRH1dIbzaPrS3CpT6DhSrOY5KPYDsJrOLCpb6Cef5EhrJ3A0NEz4J3A0NCmqJCm0J3A0dRrrMFn4J3A0
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Connection: keep-alive
返回结果
HTTP的报文头大致可以分为四类:通用报文头、请求报文头、响应报文头和实体报文头。
在HTTP/1.1中一共规范了47种报文头字段。
通用报文头:请求和响应都可以使用
报文属性名 | 说明 |
---|---|
Cache-Control | 控制缓存的行为 |
Connection | 逐条首部、连接的管理 |
Date | 创建报文的日期时间 |
Pragma | 报文指令 |
Traiker | 报文末端的首部一览 |
Transfer-Encoding | 指定报文主体的传输编码方式 |
Upgrade | 升级为其他协议 |
Via | 代理服务器的相关信息 |
Warning | 错误通知 |
请求报文头:请求使用
报文属性名 | 说明 |
---|---|
Accept | 用户代理可处理的媒体类型 |
Accept-Charset | 优先的字符集 |
Accept-Encoding | 优先的内容编码 |
Accept-Language | 优先的语言(自然语言) |
Authorization | Web认证信息 |
Expect | 期待服务器的特定行为 |
From | 用户的电子邮箱地址 |
Host | 请求资源所在服务器 |
if-Match | 比较实体的标记(ETag) |
if-Modified-Since | 比较资源的更新时间 |
if-None-Match | 比较实体标记(与if-Match相反) |
if-Range | 资源未更新时发送实体Byte的范围请求 |
if-Unmodified-Since | 比较资源的更新时间(与if-Modified-Since相反) |
Max-Forwards | 最大传输逐跳数 |
Proxy-Authorization | 代理服务器要求客户端的认证信息 |
Range | 实体的字节范围请求 |
Referer | 对请求中URI的原始获取方 |
TE | 传输编码的优先级 |
User-Agent | HTTP客户端程序的信息 |
响应报文头:响应使用
报文属性名 | 说明 |
---|---|
Accept-Ranges | 是否接受字节范围请求 |
Age | 推算资源创建经过时间 |
ETag | 资源的匹配信息 |
Location | 令客户端重定向至指定URI |
Proxy-Authenticate | 代理服务器对客户端的认证信息 |
Retry-After | 对再次发起请求的时间要求 |
Server | HTTP服务器的安装信息 |
Vary | 代理服务器缓存的管理信息 |
WWW-Authenticate | 服务器对客户端的认证信息 |
实体报文头
报文属性名 | 说明 |
---|---|
Allow | 资源可支持的HTTP方法 |
Content-Encoding | 实体主体使用的编码方式 |
Content-Language | 实体主体的自然语言 |
Content-Length | 实体的主体大小(单位:字节) |
Content-Location | 替代对应资源的URI |
Content-MD5 | 实体主体的报文摘要 |
Content-Range | 实体主体的位置范围 |
Content-Type | 实体主体的媒体类型 |
Expires | 实体主体过期的日期时间 |
Last-Modified | 资源的最后修改日期 |
ACCEPT
浏览器可以接收的媒体类型。
如果有多个,以优先级进行选择。
使用q=权重值的方式表示
ACCEPT_Encoding
浏览器申明自己接收的编码方法,通常指定压缩方法,是否支持压缩,支持什么压缩方法。
Accept-Language
浏览器申明自己接收的语言
Connection
Connection:keep-alive当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。
Connection:close代表一个Request完成后,客户端和服务器之间用于传输HTTP数据的TCp连接会关闭,当客户端再次发送Request,需要重新建立TCP连接。
Host
请求报文头域主要用于指定被请求资源的Internet主机和端口号,它通常从HTTP URL中提取出来的。
Referer
当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面连接过来的,服务器借此可以获得一些信息用于处理。
User-Agent
告诉HTTP服务器,客户端使用的操作系统和浏览器的名称和版本。
Content-Type
说明了报文体内对象的媒体类型。
响应报文
我们首先基于spring boot 创建一个web项目
GET:用于请求访问已被URI识别的资源
接着在上面创建的web项目中,创建一个get请求的服务
接着我们使用telnet进行访问。
首先开启telnet的windows服务
首先进入telnet
接着连接服务器 open 127.0.0.1 8080
当没有提示异常的时候,就表示连接成功。
此时按下回车键,光标会从左上角一直回车往下移动。
接着输入我们的get请求
GET /get/lili HTTP/1.1
Host: 127.0.0.1
然后连续按下两次回车,就是发送这个get请求了。
响应如下
当出现断开连接的时候,就需要重新open了。
当然,我们也可以增加保持连接这个属性
响应如下
这玩意太难用了,不过,linux下的好像更加难用。
post主要是避免像get一样,将参数明文附加到请求字符串上,而是将参数放在传输实体中,这样传输的数据经过封装之后,就不会直接暴露在请求地址中了。
我们在get方法的基础上增加post方法。
这里我们使用postMan测试接口可用性,然后使用fiddler抓取post请求。接着拷贝并分析抓取的报文,然后在telnet中重放。
首先我们增加post方法
接着使用postMan测试
然后打开fiddler抓取
然后查看报文
我们知道Connection是可选的。
然后在telnet中重发
请求成功
经过不停的尝试,我找到了POST请求的属性的最小子集,换句话说,一个POST报文,至少应该包含这几个属性
POST http://192.168.20.88:8080/post HTTP/1.1
Host: 192.168.20.88:8080
Content-Length: 12
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
name=xiaomei
当然,如果没有参数,应该会更少
执行结果
put是幂等的,而post是不幂等的。
put更多的时候用作传输资源。
轮到put了
方法还是一样的,先用postMan打个样,然后我们抓取报文后,看看有些报文属性,接着重发验证。
抓取到的请求
put请求的最小子集
PUT http://192.168.20.88:8080/put HTTP/1.1
Host: 192.168.20.88:8080
Content-Length: 9
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Origin: chrome-extension://lboaigfphnnfclelldpoladgpldgbcgn
name=lili
重发
结果
类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头。
HEAD是获取头信息的,而且在postMan中也无法测试。
幸好HEAD方法比较简单,我们直接在telnet中验证。
接着就会返回通用的属性信息
这是post接口的返回信息,比get多了一个allow属性
而且,注意异常码,对一个POST接口使用HEAD方法,会异常的。
那么,有没有HEAD方法的写法呢?
事实证明是可以的
请求结果
用于请求服务器删除指定的资源。
用于查询指定URI支持的方法。
比如我们查询POST方法对应的地址/post支持的方法
执行结果
回显服务器收到的请求,主要用于测试或诊断
我们故意访问一个不存在的地址
返回结果
开启一个客户端与所请求资源之间的双向沟通的通道,可以用来创建隧道。
状态码是用来表示网页服务器超文本传输协议响应状态的3位数字代码
比如第一行最后面的3位数字。
分类 | 含义 |
---|---|
1XX | 表示消息。这一类型的状态码,代表请求已被接收,需要继续处理。这类响应是临时响应,只包含状态行和某些可选的响应头信息,并以空行结束。 |
2XX | 表示成功。这一类型的状态码,代表请求已成功被服务器接收,理解。 |
3XX | 表示重定向。这类状态码代表需要客户端需要采取进一步的操作才能完成请求。通常,这些状态码用来重定向,后续的请求地址(重定向目标)在本次响应的Location域中指明。 |
4XX | 表示请求错误。这类的状态码代表了客户端看起来可能发生了错误,妨碍了服务器的处理。除非响应的是一个HEAD请求,否则服务器就应该返回一个解释当前错误状态的实体,以及这是临时的还是永久性的状态。这些状态码适用于任何请求方法。浏览器应当向用户显示任何包含在此类错误响应中的实体内容。 |
5XX | 表示服务器错误。这类状态码代表了服务器在处理请求的过程中有错误或者异常状态发生,也有可能是服务器意识到以当前的软硬件资源无法完成对请求的处理。除非这是一个HEAD请求,否则服务器应当包含一个解释当前错误状态以及这个状况是临时的还是永久的解释信息实体。浏览器应当向用户展示任何在当前响应中被包含的实体。 |
2XX
状态码 | 状态码英文信息 | 描述 |
---|---|---|
200 | OK | 请求已成功,请求所希望的响应头或数据体将随此响应返回 |
202 | Accepted | 已接受,已经接收请求,但未处理完成 |
206 | Partial Content | 部分内容,服务器成功处理了部分GET请求 |
3XX
状态码 | 状态码英文信息 | 描述 |
---|---|---|
301 | Moved Permanently | 永久移动,请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新的URI。今后任何新的请求都应使用新的URI代替 |
302 | Found | 临时移动,与301类似。但资源只是临时被移动。客户端应继续使用原有URI |
4XX
状态码 | 状态码英文信息 | 描述 |
---|---|---|
400 | Bad Request | 客户端请求的语法错误,服务器无法理解 |
401 | Unauthorized | 请求要求用户的身份认证 |
403 | Forbidden | 服务器理解请求客户端的请求,但是拒绝执行此请求 |
404 | Not Found | 服务器无法根据客户端的请求找到资源(网页)。 |
5XX
状态码 | 状态码英文信息 | 描述 |
---|---|---|
500 | Interbal Server Error | 服务器内部错误,无法完成请求 |
502 | Bad Gateway | 充当网关或代理的服务器,从远端服务器接收到了一个无效的请求 |
因为HTTP请求时无状态的,无状态的HTTP请求在处理业务逻辑的时候就比较吃力,每次都需要将之前的数据重新传输给服务器,不仅仅传输非常耗时,而且参数增加,url地址也是会变的很长。
为了解决这个问题,就需要有一种机制,既可以让客户端看到数据,又能在一定程度上保证数据的安全。
就像我们积分制的兑换卡一样,我们去超市购物,超市会和我们所要手机号或者身份证号码,用户查找会员,这样就能将本次购物的积分累加上去。而我们用户在每次购物完成后,会得到一张小票,小票上就会显示本次积分值和总积分值。
同样的道理,HTTP想要实现类似的效果,和我们超时办理会员的流程差不多。
首先,客户端登录服务端,服务端生成客户端的认证信息,也就是session。
服务端生成session后,就会返回sessionId给客户端,同时会将不敏感的信息给客户端传输一份。
客户端得到了sessionId和session里面不敏感的信息,接着浏览器会将不敏感的信息持久化一份(一般是直接明文存储在文件中)。这就是Cookie。
而服务端生成的session因为里面包含敏感信息,所以一般就存储在内存中,并不会持久化。这样更安全。这就是session。
有关cookie和session更详细的内容请看
jsp初体验之session
身份认证包括密码、动态令牌、数字证书、生物认证、IC卡等等。
常见的认证方式
BASIC认证(基本认证)
BASIC认证就是你访问一个网站,然后浏览器弹出一个验证框,要求输入用户名、密码。
一般在tomcat中比较常见
我们打开抓包软件
发现我们请求tomcat的manage项目,在没有经过验证的时候,就会返回401错误,要求我们进行验证
此时浏览器就会显示登陆界面要求我们输入用户名和密码。
返回的haeder中有一个www-authenticate:BASIC realm="Tomcat Manager Application"的属性
在我们输入用户名密码后,会带着一个验证的属性重新请求
这整个过程是这样的:
在199x年左右,反向解码一个base64编码的字符串还是比较困难的。
但是因为现在有很多网站使用字典的方式,记录了大量的字符串以及对应的base64编码,所以,使base64编码破解成为了可能。
换句话说,使用BASIC的方式进行验证,那么,用户的用户名和密码敏感信息就是在裸奔。所以现在几乎不再使用这种方式验证身份。
DIGEST认证(摘要认证)
为了弥补BASIC认证存在的弱点,从HTTP/1.1起就有了DIGEST认证。
DIGEST认证同样使用质询/响应的方式,但不会想BASIC认证那样直接发送明文密码
DIGEST认证在客户端请求的时候,第一次也是返回401.同样也会有www-authenticate: Dgest realm="DIGEST"属性
区别在于这次多了其他的信息,比如nonce,algorithm,qop等等。
这些属性用于指定客户端对密码进行加密的时候,需要使用什么样的附加串,使用什么加密规则等等。
基本过程可以认为是这样的:
服务器端随机生成质询码,然后指定加密方式。
客户端基于质询码,附加上用户输入的密码使用服务器指定的加密方式进行加密,然后在下一次请求的时候,会在这些信息上附件上计算后的响应码。
服务器端使用相同的质询码,以及加密方式,使用服务器持有的密码进行加密,然后将加密后的数据和响应码进行比对。
通过就会返回200,否则就会返回401.
这样做的好处在于,初始的质询码是随机的,虽然可能被其他人获取到加密后的信息和加密方式,但是因为不知道初始值,所以破解就在原来的基础上增加了一定的难度,和一定的计算量。
SSL客户端认证
SSL客户端认证是借由HTTPS的客户端证书完成认证的方式。凭借客户端证书认证,服务器可以确认访问是否来自已登录的客户端
因为这种方式涉及到数字证书的申请和颁发等等信息,而且每次请求都需要使用证书加密整个请求,所以性能不是很好。不过这种方式比起前面两种方式能更加安全。别人即使等到了数据报文,也无法进行破解。
数字证书就是基于一定的规则,生成一个公钥和一个私钥。将公钥传输给客户端浏览器,浏览器每次请求之前使用公钥进行加密,然后将加密后的请求发送给服务端。服务端收到加密后的请求后,使用自己持有的私钥进行解密,然后将解密后的请求在传输给对应的接口。
因为每一次请求都涉及到加密和解密,而且第一次请求还需要安装证书,特别是涉及到ca根证书的签名等等。
成本还是比较大的。
更多关于证书的信息可以参考
tomcat实现https双向认证配置
FromBase认证(基于表单认证)
这个就很常见了,就是将登陆的信息使用from表单提交。
对于表单提交密码,如果是https的方式提交,那么就是安全的,破解很难。
即使拦截到了报文信息,也是加密后的信息。安全程度就高了很多。
如果表单提交密码,而且是http的方式提交,那么拦截到提交的报文,密码也就被泄露了。
比如这个post请求,因为没有采用https的方式提交内容,用户名密码等敏感信息就在post内容中。
所以,目前基本上都是使用https+表单的方式验证用户的身份的。
如果你还在使用http+表单验证用户身份,那么就需要注意用户密码被泄露的风险了。
HTTP协议是基于请求/响应模式的,因此只要服务端给了响应,本次HTTP请求就结束了。
在HTTP1.0和0.9的时候,因为客户端访问的界面简单,服务器端计算能力低下,因此,默认是HTTP请求结束,本次TCP连接也就断开了。
所以HTTP的长连接和短连接实际上是TCP的长连接和短连接。
TCP每一次连接都需要进行三次握手,所以,TCP建立一次连接需要耗费的资源是不少的。
现在一个页面,访问好几十次,是很常见的,那么需要建立好几十次TCP连接,此时累积的资源耗费就比较客观了。
因此后续HTTP协议增加了一个属性Connection,里面的值如果是keep-alive就是长连接,是close表示断开连接。
默认是短连接。
使用长连接后,TCP连接就会长时间保持(不是一直保持,有一个默认的超时时间,一般是60s)。
如果在超时时间内再次请求,就会复用这个保持的TCP连接。
同时,如果在请求的时候再次使用了Connection: keep-alive属性,那么就相当于给这个TCP连接进行了续约。
否则超时时间一到,还是会断开连接的。
因为有这默认的超时时间,所以现在的浏览器请求的时候都会一直续约,在离开的时候,会主动断开。
如果是强制关闭浏览器,那么超时了,服务端会断开连接。
我们在前面的长连接和短连接中讲到,客户端请求服务端,需要不停的创建连接,而服务端不仅仅需要响应请求,还需要对请求的内容进行计算。所以,在一定程度上保持单一原则,将连接的创建与服务端计算进行分离。就出现了代理服务器。比如客户端和代理服务器之间是短连接,而代理服务器和后端服务器之间是长连接。而且代理服务器会缓存一定的数据,降低服务器静态资源的压力。比例nginx就是一个很强大的代理工具。
还有,使用了代理更加安全。客户端要访问服务端,必须通过代理服务器进行访问,所以,我们暴露给网络的是代理服务器,而不是真正的服务器。这样,当代理服务器出现问题,或者代理服务器被安全攻破的时候,只会影响到代理服务器,而且,代理服务器上不会存储很多的重要的数据,只是缓存一些不重要的静态资源。
所以,在一定程度上,使用代理服务器能保证真正的服务器的安全。
代理不仅仅有上述好处,还有一个作用就是抓包,有了代理服务器,我们就可以统计请求的数据,包括请求的类型数量等等。
代理服务器不仅仅保护服务端,对于服务器端来说,隐藏客户端的信息也很重要,所以,代理服务器可以实现匿名访问,相对于客户端和服务器端,都是匿名的。服务端不知道客户端,客户端不知道服务器端。客户端和服务器端的连接都是通过代理服务器。
最近代理服务器用的很火的一个作用:数据过滤。对于服务器端来说,你请求什么我就响应什么,没有我就404.但是如果是非法用户进行的访问,或者说,需要确认身份的访问,这时候放在服务端就比较重了。所以可以将数据过滤的工作放在代理服务器上。比如禁止访问包含政治话题的数据,禁止访问指定屏蔽词的数据,禁止访问色情信息等等。
网关可以作为某种翻译器使用,他抽象出了一种能够到达资源的方法。网关是资源和应用程序之间的粘合剂。网关扮演的是"协议转换器"的角色。
网关和代理的区别
web网关在一侧使用http协议,在另一侧使用另一种协议。
<客户端协议>/<服务器端协议>
(HTTP/)服务器端网关:通过http与客户端对话,通过其他协议与服务器通信。因为网关对于客户端来说,扮演的服务器的角色,所以是服务器端网关。
(/HTTP)客户端网关:统计过其他协议与客户端对话,通过HTTP协议与服务器通信。因为网关对于服务端来说,扮演的是客户端的角色,所以是客户端网关。
网关常用的类型
在一个网站上,不同的界面有着相同的网站头,网站菜单等等,甚至一些相同的图片,样式等等。这些数据变更的频率比较低。还有些网站首页会自动播放一些滚动图,这些滚动图也是静态资源,甚至是视频等等。
缓存的控制属性:Cache-Control
请求、响应头,缓存控制字段。
no-store:所有内容都不缓存
no-cache:缓存,但是浏览器使用缓存前,都会请求服务器判断资源是否是最新
max-age=x(单位秒)请求缓存后的x秒不在发起请求
s-maxage=x(单位秒)代理服务器请求源站缓存后的x秒不在发起请求,只对CDN缓存有效
public:客户端和代理服务器(CDN)都可缓存。
private:只有客户端可以缓存。
缓存的过期属性:Expires。
响应头。代表资源过期时间,由服务器返回提供,是http1.0的属性,在于max-age共存的情况下,优先级低。
缓存的修改属性:Last-Modified
响应头,资源最新修改时间,由服务器告诉浏览器。
if-Modified-Since
请求头,资源最新修改时间,由浏览器告诉服务器,和Last-Modified是一对,会进行对比。
Etag
响应头,资源标识。服务器告诉浏览器。
if-None-Match
请求头,缓存资源标识,有浏览器告诉服务器(服务器上次给的Etag),和Etag是一对,会进行比较。
缓存的工作方式:
过期时间:在过期时间之前,浏览器使用本地缓存的数据,超过过期时间,则重新向服务器请求。
过期时间+修改时间:在过期时间之前,浏览器使用本地缓存的数据,超过过期时间,每次请求前,先拿着修改时间和服务器的修改时间对比,看看缓存文件是否被更新。如果缓存文件根本没有被更新,那么就不需要重新下载缓存数据。
过期时间+修改时间+maxage+Etag:这种是属于过期时间很长,但是不请求,不对比服务器资源,直接使用缓存的时间使用maxage指定的时间。比如资源可能每2分钟更新一次,但是这个2分钟不是具体值,而是平均值,资源修改的时间范围是1~3分钟之间,属于不确定的。
此时使用过期时间就不太合适,设置太小,起不到缓存的作用,设置过程,容易将被污染的缓存数据被使用。
基于这个原因,增加maxage属性和Etag属性。maxage属性告诉浏览器,在maxage的时间内,我可以保证资源一定不会被修改,但是超过这个时间则不一定。
对于资源很多的时候,如何描述资源,也是一个问题。服务器端返回资源的表示Etag,后面客户端在请求这个资源的时候,就可以使用Etag来代指资源。
上述三种方案,都是乐观的认为在指定时间内,缓存一定的最新的,一定不会修改。但是凡事都有例外,客户端无法主动感知资源的变化,只能通过时间被动的感知到资源是否发生了变化,从而决定是否更新资源。
所以,给静态资源增加唯一标识码,比如md5值,或者hash缓存,就是一个有效方案。
在有效时间内,每隔指定时间,就去对比唯一码,来确定资源是否发生了修改。
CND缓存。
CDN是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。
浏览器操作对HTTP缓存的影响
用户操作 | Expires/Cache-Control | Last-Modified/Etag |
---|---|---|
地址栏回车 | 有效 | 有效 |
页面连接跳转 | 有效 | 有效 |
新开窗口 | 有效 | 有效 |
前进、后退 | 有效 | 有效 |
F5刷新 | 无效 | 有效 |
Ctrl+f5刷新 | 无效 | 无效 |
指客户端和服务器端就响应的资源内容进行交涉,然后提供给客户端最为合适的资源。内容协商会以响应资源的语言,字符集,编码方式等作为判断的基准。
内容协商说白了就是选择国际化。
内容协商的方式:
客户端驱动:
客户端发起请求,服务端发送可以提供的列表,客户端做出选择,重新发起请求。
服务器驱动
服务器收到请求后,检查客户端的请求头部属性,并决定提供哪个国际化的页面。
透明协商
通过中间设备(比如代理)代表客户端协商。
内容协商的相关的属性(请求)
内容协商近似匹配
比如
Accept-Language: en;q=0.5,fr;q=0.0,zh;q=1.0
这个表明:我不接受法语,最好是中文。在没有中文的情况下返回英文。
断点续传如何实现的?
在浏览器下载文件,都有一个功能,断点续传。那么,这个功能是如何实现的呢?
HTTP是通过在Header里两个参数实现的,客户端发起请求时对应的是Range,服务器端响应时对应的是Content-Range。
Range
用于请求头中,指定第一个字节的位置和最后一个字节的位置.
Range:(begin)-[end](单位:字节)
Content-Range
用于响应头中,在发出带Range的请求后,服务器会在Context-Range头部返回当前接收的范围和文件总大小
Context-Range:(begin)-[end]/[length]
断点续传的响应
HTTP/1.1 200 OK (不使用断点续传方式)
HTTP/1.1 206 Partial Content (使用断点续传方法)
HTTPS:HTTP+TLS
TLS是传输层加密协议,前身是SSL协议。
HTTPS内容加密(报文加密),身份认证(数字证书),数据完整(防止篡改)。
内容加密:
http协议有一个非常致命的问题,报文的传输是明文传输。明文传输会带来一系列的问题,比如信息、隐私的泄露,请求的篡改等等。
为了解决这些问题,就需要对报文进行加密。
加密有对称加密和非对称加密。
对称加密是指加密和解密使用相同的秘钥。
非对称加密是指加密使用公钥,解密使用私钥。
相比来说,非对称加密是比对称加密更加安全。
对称加密就意味着解密的秘钥也被告知了客户端,以及秘钥的传输,秘钥的拦截,窃听等等。
非对称加密更加安全,因为对外暴露的都是公钥,对于公钥,我是不怕泄露的,因为加密和解密必须同时使用公钥和私钥。也就是公钥加密,私钥解密;或者私钥加密,公钥解密。
那么,这样就万无一失了吗?非也。
公钥是用来加密的,如果我拦截了公钥,对公钥做了替换。比如我们前面提到,代理服务器主要就是做拦截工作的。
我可以在客户端和服务器端中间部署一个代理服务器。
客户端来请求的时候,先到代理服务器,代理服务器接受到这个请求,将请求转发到服务器端。
服务器端约定使用非对称加密,公钥是key1.然后服务器端将响应返回给代理服务器。
代理服务器接收到响应,替换了代理服务器自己生成的密钥对的公钥key2.
然后替换响应报文中的key1,然后将响应返回给客户端。
客户端使用key2加密信息,然后将加密后的请求报文发送给代理服务器。
代理服务器自己有key2的私钥,就可以进行解密,得到明文报文。
接着代理服务器将明文报文做个备份,然后用真正的key1进行加密,然后用加密后的报文请求服务端。
服务端收到请求,使用key1对应的私钥进行解密,然后做出响应。然后使用私钥加密。
世界上没有绝对的安全。
为了解决这个问题,就找一个权威的机构做证书的管理(ca机构)(不仅仅有ca机构)
ca机构申请证书需要成本的,所以一些银行的证书会被浏览器提示不可信。因为银行的证书没有经过ca机构的认证。
因为银行认为ca机构不可信。。。
证书费用以及更新维护
现在有免费证书,收费证书也不是很贵(也有贵的)。
降低用户访问速度。现在计算能力的提高,速度影响不是很明显了。
消耗CPU资源。用户请求需要加密,服务端就需要解密。客户端加密的资源消耗不是很明显,但是服务端解密的CPU资源消耗就不能简单的忽略了。
tomcat实现https双向认证配置
三次握手,四次挥手。
影响HTTP网络请求的因素:
带宽:
在早期,带宽是影响HTTP网络请求的因素的主要原因。
延迟:
HTTP协议的瓶颈
WebSocket可以看做是HTTP为了更好的适应长连接而做的大补丁。
WebSocket兼容HTTP,但是与HTTP协议并不完全相同。
WebSocket与HTTP有相同之处。
HTTP是非持久化的协议:
在短连接中,一个请求一个响应,就是一次HTTP的完整的生命周期。
在长连接中,一个请求串行一个响应,而且一个请求,必然对应一个响应。一次连接的建立与断开,就是一次HTTP长连接的完整的生命周期。
WebSocket和HTTP非常类似(毕竟WebSocket还是兼容Http请求的)
HTTP轮询资源更新。
AJAX轮询:浏览器间隔指定时间,请求服务器,资源是否更新。
Long Poll(长轮询):浏览器请求服务器,服务器不会立即返回,当资源发生更新时,服务器才返回响应。在没有资源更新的期间,整个请求被阻塞在了服务端。
这也是HTTP被动型的一个体现。
缺点:
AJAX轮询:服务器返回响应必须非常快。
Long Poll(长轮询):服务器必须有足够高的并发量(阻塞状态下,连接不会断开,这样对服务器的并发数有很大的要求)
WebSocket优化:
客户端选择websocket协议,当服务端切换到websocket模式,和客户端建立连接后,当服务器有资源更新时,服务器可以主动推送消息给客户端。
使用异步回调的方式,解决了HTTP同步的问题。
因为转为了异步回调的方式,对于服务器的并发要求也就降低了
WebSocket最大的改进就是将通信从半双工修改为全双工模式。
WebSocket只需要建立一次连接,所以就减少了通信量。
WebSocket节省了大量的header的传输。
WebSocket支持多路复用。
WebSocket常用于聊天,实时刷新等场景。(WebSocket埋个坑。。)
SPDY(读作“SPeeDY”)是Google开发的基于TCP的会话层 协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验。SPDY并不是一种用于替代HTTP的协议,而是对HTTP协议的增强。新协议的功能包括数据流的多路复用、请求优先级以及HTTP报头压缩。谷歌表示,引入SPDY协议后,在实验室测试中页面加载速度比原先快64%。
HTTP的缺点:
SPDY改进:
HTTP 2.0 性能增强的核心:二进制分帧
HTTP 2.0 增加了一个二进制分帧层。
二进制分帧层将header和data分开,而且支持双向通信。对于headers和data 可以乱序传输。
headers和data乱序传输后,根据二进制帧的需要,在重新组装起来。
HTTP2.0的优化
HTTP2.0首部压缩
只有第一次会发送头部,后续只要头部属性没有发生变更,那么就不会在重复发送头部属性。
头部属性表在客户端和服务器端都会存储。
多路复用
因为在HTTP2.0中增加了二进制分帧层,而且二进制帧可以乱序传输。
那么对于一个连接,传输多个请求就不是问题了。
对于多个请求,共用一个连接,直接发送即可。
服务端收到请求后,在重新组装二进制帧,在解析出请求。
吞吐量增加
因为使用多路复用,所以,相同连接数下,吞吐量就大大增加了。
并行双向数据传输
因为有分帧和乱序传输,而且在数据传输过程中,一般发送和接受,在硬件的不同引脚上。也就是说,服务器端和客户端都可以同时接受和发送。
这样在相同时间内,传输速度就增加了一倍。
请求优先级
在多个并发请求的时候,由优先级决定服务器先处理哪个请求。
优先级也不是绝对的,在高优先级的数据帧还未传输完成时,此时如果低优先级的请求的数据帧已经传输完整,那么就先处理低优先级的请求。
优先级也有混合优先级模式
服务器推送
HTTP2.0也支持服务器推送消息
WebDAV (Web-based Distributed Authoring and Versioning) 一种基于 HTTP 1.1协议的通信协议。它扩展了HTTP 1.1,在GET、POST、HEAD等几个HTTP标准方法以外添加了一些新的方法,使应用程序可对[Web Server](https://baike.baidu.com/item/Web Server/9306055)直接读写,并支持写文件锁定(Locking)及解锁(Unlock),还可以支持文件的版本控制。
现在一些在线网盘都支持在计算机上创建一个虚拟硬盘,在虚拟硬盘中可以直接操作文件。
还有比如一些浏览器管理服务器文件等等。
比如Jumpserver,就支持WebDAV协议,可以在浏览器中操作文件。
WebDAV追加方法
方法 | 用途 |
---|---|
PROPFIND | 获取属性 |
PROPPATCH | 修改属性 |
MKCOL | 创建集合 |
COPY | 复制资源及属性 |
MOVE | 移动资源 |
LOCK | 资源加锁 |
UNLOCK | 资源解锁 |
WebDAV新增状态码
状态码 | 含义 |
---|---|
102:Processing | 可正常处理请求,但目前是处理中状态 |
207:Multi-Status | 存在多种状态 |
422:UnprocessibleEntity | 格式正确,内容有误 |
423:Locked | 资源已被加锁 |
424:FailedDependency | 处理与某请求关联的请求失败,因此不再维持依赖关系 |
507:InsufficientStorage | 保存空间不足 |
QUIC(Quick UDP Internet Connection)是谷歌制定的一种基于UDP的低时延的互联网传输层协议。在2016年11月国际互联网工程任务组(IETF)召开了第一次QUIC工作组会议,受到了业界的广泛关注。这也意味着QUIC开始了它的标准化过程,成为新一代传输层协议 [1] 。
HTTP2.0的缺点
QUIC改进
0 RTT:在QUIC中客户端和服务端会缓存头部属性,只要头部属性验证通过,就可以直接建立连接。包括建立加密连接。
无头部阻塞的多路复用:因为QUIC的头部属性采用的是缓存加验证模式,所以,如果属性没有发生更改,请求是不会重新传输头部属性的。也就不存在头部阻塞了。当然QUIC本身还是支持多路复用的。
对于数据包丢包的情况,因为HTTP2.0是基于TCP协议,所以当出现丢包,必须重传丢失的数据包,后面的数据即使到了,也无法解析并使用。
而QUIC是基于UDP协议,当丢包的数据包在等待重传的时候,后面的数据包已经到了,就会解析处理后面的数据,并不会阻塞等待丢包的请求。
FEC(前向纠错):前向纠错也叫前向纠错码(Forward Error Correction,简称FEC),是增加数据通讯可信度的方法。在单向通讯信道中,一旦错误被发现,其接收器将无权再请求传输。FEC 是利用数据进行传输冗余信息的方法,当传输中出现错误,将允许接收器再建数据。
FEC在数据包中冗余部分信息,如果在传输的过程中出现丢包,那么就可以使用纠错的方式从冗余数据中计算出丢失包的数据,从而避免重传。(因为重传意味着重新分割帧,重新计算等等,甚至包括建立连接)
需要注意的是,丢包只在丢1个包的时候才能计算出,如果丢多个包,就无法计算出了(计算出来的数据,也不知道那些数据属于哪个包)
如何查看自己现在使用的http版本呢?
我们首先使用浏览器的开发者工具(谷歌浏览器、edge是f12)
接着刷新界面,此时在开发者工具中会展示有请求发出
接着我们随机选择一个请求,右键
然后打开文本编辑器,粘贴,找到我们的请求
里面的httpVersion很清楚的标明了是HTTP1.1版本。
升级HTTP2.0也很容易
在微服务的application.properties和application.yaml中增加配置
然后重启微服务并访问,然后拷贝数据到文本编辑器中找到请求
这样就升级为了http2.0了
远着呢航机制是应用程序防御恶意攻击的核心机制。它处在安全防御的最前沿,如果被用户轻易突破,通常应用程序的全部功能、数据都会被控制。
进行的身份验证模式
验证技术:
常见的问题
验证模式有一个绕不开的问题,就是暴力破解。对于暴力破解,应用程序应该有一定的机制,防止暴力破解。
防止暴力破解常用有这些方式
在大多数的Web应用程序中,会话管理机制是一个基本的安全组件。
会话id生成规律,简单加密,伪随机等等。
会话终止在一定程度上能够保护会话安全。
伪退出,客户端退出,但是服务器端并没有真正的销毁session。客户端退出后,依然可以使用session。
会话应使用加密连接传输。
会话过期。(软过期,硬过期)
SQL注入核心是将参数通过字符串拼接的方式拼接到SQL中,在执行SQL的时候,直接执行。
常见的就是在登录的时候,执行查询语句,通过字符串拼接的方式拼接SQL,通过SQL注入获取目标数据。
有了SQL注入,就能查询user_table等表或者视图,这样就能够嗅探整个数据库的结构。从而获取关键机密信息。
使用SQL注入,也可以提升权限。
如何防御
不要使用拼接方式,而是使用参数绑定的方式执行SQL。
甚至检查输入的参数,不允许一些和SQL注入有关的参数输入。
设置过滤名单,记录IP不能使用,某些关键词不能用等等。
Cross Site Scripting。
xss,跨站脚本攻击。
xss允许恶意web用户将代码植入到提供给其他用户使用的页面中。其他用户在观看网页时,恶意脚本就会执行。
xss通常通过注入HTML或JS脚本等发动攻击。
攻击成功后,就会得到私密网页的内容和cookie等等。拿到cookie就在一定程度上拿到目前有效的sessionId,然后就可以借用这个sessionId查询想查询的数据了。
xss攻击分类:
反射式xss
非永久性xss。
在用户提交的数据没有做无害化处理,那么就会发生xss攻击。
存储式xss
永久性xss。
将恶意脚本存储到服务端,在查看的时候,使得恶意脚本被执行。
基于DOM的xss
基于DOM的攻击仅仅通过JS方式执行。
攻击目标:
防御:
))Cross-site Request Forgery
跨站请求伪造。
xss利用站点内的信任用户(受害者),而CSRF通过伪装来自受信任用户的请求来访问受信任的网站。
csrf是通过社会工程学的手段,来蛊惑受害者进行一些敏感性的操作。而受害者还不知道自己已经受到攻击。
csrf的破坏力依赖于目标用户的权限。
csrf的原理:
网站在登录后,每次请求都会将自己的身份验证令牌带上。
用简单的话来说,就是每个请求都会带有sessionId,如果我在我自己的信息上发布了一个csrf的脚本,脚本每当在其他浏览器中展示,就会使用其他浏览器登录的用户的身份执行一些操作。这样就是跨站请求伪造。
防御: