目录
一、DNS
二、NAT
1、技术背景
2、NAT机制IP转化过程
三、NAPT
NAT技术的缺陷
四、HTTP
1、协议格式
2、HTTP请求
1)method(方法)
GET请求的特点
POST请求的特点
GET和POST的区别
2)URL(网址)
基本格式
关于URL encode
3)Header(请求报头) 与 body(正文)
3、HTTP响应
1)status code(状态码)
2)Header(响应报头)
4、通过form表单构造HTTP请求
1)发送GET请求
2)发送POST请求
主要的区别:
5、通过ajax构造HTTP请求
1)引入jquery库
2)编写代码
①发送get请求
②发送POST请求
6、HTTP下发生的运营商劫持
五、HTTPS
工作过程
1、引入对称加密
2、引入非对称加密
1)公钥和私钥
2)加密过程
3、引入证书
获取公钥
确保公钥的真实性
完整流程
总结
六、Tomcat
一、DNS
DNS,Domain Name System,域名系统。DNS是一整套从域名映射到IP的系统
TCP/IP中使用IP地址来确定网络上的一台主机,但是IP地址不方便记忆,且不能表达组织信息,于是人们发明了域名,并通过域名系统来映射域名和IP地址
域名是一个字符串,如www.baidu.com,hr.nowcode.com
域名系统为一个树形结构的系统,包含很多节点,其中:
1、根节点即根域名服务器,最早IPV4的根域名服务器全球只有13台,IPV6在此基础上扩充了数量
2、子节点主要由各级DNS服务器或DNS缓存构成
DNS域名服务器,即提供域名转换为IP地址的服务器
浏览器、主机系统、路由器中都保存DNS缓存
Windows系统的DNS缓存在C:\Windows\System32\drivers\etc\hosts文件中;Mac/Linux系统的DNS缓存在/etc/host文件中
网络通信发送数据时,如果可以使用目的主机的域名,需要先通过域名解析查找到对应的IP地址
域名解析的过程,可以简单地理解为:发送端主机作为域名系统树形结构的一个子节点,通过域名系统信息,从下到上查找对应的IP地址的过程。如果到根节点(根域名服务器)还找不到,即找不到该主机
域名解析使用DNS协议来传输数据。DNS协议是应用层协议,基于传输层UDP或TCP协议来实现
二、NAT
1、技术背景
在文章网络层重点协议—IP协议中我们提到了IPV4协议中存在IP地址数量不充足的问题
NAT能够将私有IP对外通信时转为全局IP,也就是就是一种将私有IP和全局IP相互转化的技术方法
很多学校、家庭、公司内部采用每个终端设置私有IP,而在路由器或必要的的服务器上设置全局IP
全局IP要求唯一,但是私有IP不需要;在不同的局域网中出现相同的私有IP是完全不影响的
2、NAT机制IP转化过程
NAT路由器将原地址从10.0.0.10替换成全局的IP 202.244.174.37
NAT路由器收到外部的数据时,又会把目标IP从202.244.174.37替换回10.0.0.10
在NAT路由器内部,有一张自动生成的用于地址转换的表,当10.0.0.10第一次向163.221.120.9发送数据时就会生成表中的映射关系
三、NAPT
那么问题来了,如果局域网内有多个主机都访问同一个外网服务器,那么对于服务器返回的数据中,目的IP是相同的。那么NAPT路由器如何判定将这个数据包转发给哪个局域网的主机?
这时候NAPT来解决这个问题了。使用IP+port来建立这个关联联系
NAT技术的缺陷
由于NAT依赖这个转换表,所以有诸多限制:
- 无法从NAT外部向内部服务器建立联系
- 转换表的生成和销毁都需要额外开销
- 通信过程中一旦NAT设备异常,即使存在热备,所有的TCP连接也都会断开
四、HTTP
1、协议格式
HTTP是一个文本格式的协议,可以通过Chrome开发者工具或者Fiddler抓包,分析HTTP请求响应的细节(Fiddler下载链接)
抓包工具的原理:
Fiddler相当于一个代理。浏览器访问sougo.com时就会把HTTP请求先发给Fiddler,再把请求转发给sougo的服务器;当sogo服务器返回数据时,Fiddler拿到返回数据再把数据交给浏览器。
因此Fiddler对于浏览器和sogou服务器之间交互的数据细节都是非常清楚的。
以下是一个HTTP请求/响应抓包的结果:
1)HTTP请求
- 首行:[方法]+[url]+[版本]
- Header(请求的属性):冒号分隔的键值对,每组属性之间使用\n分隔,空行表示Header部分结束
- Body(空行后面的部分):若存在则在Header中会有一个Content-Length属性来标识Body长度;允许为空字符串
2)HTTP响应
- 首行:[版本号]+[状态码]+[状态码解析]
- Header(请求的属性):冒号分隔的键值对,每组属性之间使用\n分隔,空行表示Header部分结束
- Body(空行后面的部分):若存在则在Header中会有一个Content-Length属性来标识Body长度;允许为空字符串;如果服务器返回了一个html页面那么html页面内容就是在body中
为什么HTTP报文中要存在空行?
因为HTTP协议并没有规定报头部分的键值对有多少个,空行就相当于是“报头的结束标记”,或者是“报头和正文之间的分隔符”;HTTP在传输层依赖TCP协议,TCP是面向字节流的,如果没有这个空行就会出现“粘包问题” 。
2、HTTP请求
- 首行:[方法]+[url]+[版本]
- Header(请求的属性):冒号分隔的键值对,每组属性之间使用\n分隔,空行表示Header部分结束
- Body(空行后面的部分):若存在则在Header中会有一个Content-Length属性来标识Body长度;允许为空字符串
1)method(方法)
GET请求的特点
- 首行的第一部分为GET
- URL的查询字符串可以为空
- Header部分有若干个键值对结构
- Body部分为空
POST请求的特点
- 首行的第一部分为POST
- URL的查询字符串一般为空
- Header部分有若干个键值对结构
- Body部分一般不为空(body内的数据格式通过Header中的Content-Type指定,body的长度由Header中的Content-Length指定)
GET和POST的区别
- 语义不同:GET一般用于获取数据;POST一般用于提交数据
- GET的body一般为空,需要传递的数据通过查询字符串传递;POST的查询字符串一般为空,需要传递的数据通过body传递
- GET请求一般是幂等的,POST请求一般不是幂等的(如果多次请求得到的结果一样就视为请求是幂等的)
- GET可以缓存,POST不能被缓存
补充说明:
- 语义:GET完全可以用于提交数据,POST也完全可以用于获取数据
- 幂等性:标准建议GET实现为幂等的。实际开发中GET也不必完全遵守
- 安全性:是否安全取决于前端在传输密码等敏感信息时是否进行加密,这和方法完全无关(POST比GET更安全 X)
- 传输数据量:标准没有规定GET的URL长度,也没有规定POST的body长度,传输数据量的多少完全取决于不同浏览器和不同服务器之间的实现区别(GET传输的数据量小,POST大 X)
- 传输数据类型:GET的查询字符串虽然无法直接传输二进制数据,但是可以针对二进制数据进行url encode。(GET只能传输文本数据,POST可以传输二进制数据 X)
2)URL(网址)
基本格式
URL,Uniform Resource Locator 统一资源定位符,就是我们平时俗称的”网址“
互联网上的每一个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它
URL的详细规则由因特网标准RFC1738进行了约定
来看一个具体的URL: https://v.bitedu.vip/personInf/student?userId=10000&classId=100
可以看到在这个URL中有些信息被忽略了,其实是都可以省略的
- https:协议方案名(常见的有http和https、jdbc:mysql)
- user:pass:登录信息(现在的网站进行身份认证一般不再使用URL)
- v.bitedu.vip:服务器地址(此处是一个域名,会通过DNS系统解析成具体的IP地址;省略后表示服务器的IP/域名与当前HTML的一致)
- 端口号:当省略时浏览器会根据协议类型自动决定使用哪个端口(http:80;https:443)
- /personInf/student:带层次的文件路径(省略后相当于/.,有些服务器会在发现/路径时自动访问/index.html)
- userId=10000&classId=100:查询字符串(键值对结构,键值对之间&分隔,键与值之间=分隔)
- #ch1:片段标识(主要用于页面内跳转)
关于URL encode
像/?:+-这样的字符已经被URL当作特殊意义使用了,是不能随意出现的。当某个参数中需要带有这些特殊字符就必须先对这些字符进行转义。
一个中文字符由UTF-8或者GBK这样的编码方式构成,虽然在URL中没有特殊含义,但也仍然需要进行转义,否则浏览器可能会把UTF-8/GBK编码中的某个字节当作URL中的特殊符号。
转义规则:将需要转码的字符转为16进制,然后从右到左取4位(不足4位直接处理),每2位做1位,前面加上%XY格式。例如下图中+就被转换成了%2B:
3)Header(请求报头) 与 body(正文)
报头的种类有很多,这里只介绍几个:
①host:表示服务器主机的地址和端口
②Content-Length:body中的长度
③Content-Type:表示请求的body的数据格式
常见选项:
④User-Agent(UA):表示浏览器/操作系统的属性
使得服务器能够识别客户使用的操作系统及版本、CPU类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。通过解析User-Agent关键词,服务器可以根据客户端的特征,提供适合的响应内容,或进行设备兼容性的优化
- Windows NT 10.0; Win64; x64 操作系统信息
- AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 浏览器信息
⑤ Cookie
Cookie是一种在客户端存储的小型文本文件,可能是客户端(网页)自动通过JS写入的,也可能是由服务器发送到用户的浏览器,然后由浏览器保存。它主要用于跟踪用户的会话信息、个性化用户体验以及存储用户偏好设置等方面。
网站通常会在使用Cookie时提供隐私政策和选择接受或拒绝Cookie的选项,以便用户能够更加自主地控制自己的数据。
往往可以通过这个字段实现”身份标识“的作用。
每个不同的域名下都可以有不同的Cookie,不同的网站之间的Cookie并不冲突。
3、HTTP响应
1)status code(状态码)
状态码表示访问一个页面的结果(是返回成功还是失败,还是其他的一些情况)
- 200 OK 访问成功
- 301 Moved Permanently 永久重定向(也是通过Location字段来表示要重定向到新的地址)
- 302 Move temporarily 临时重定向
- 403 Forbidden 没有权限访问资源
- 404 Not Found 请求的资源在服务器上不存在
- 405 Method Not Allowed 服务器不支持此method方法
- 500 Internal Server Error 服务器崩溃
- 504 Gateway Timeout 负载过大,服务器处理超时
2)Header(响应报头)
- text/html : body 数据格式是 HTML
- text/css : body 数据格式是 CSS
- application/javascript : body 数据格式是 JavaScript
- application/json : body 数据格式是 JSON
- image/png:body数据格式是图片
4、通过form表单构造HTTP请求
form(表单)是HTML中的一个常用标签,可以用于给服务器发送GET或POST请求
1)发送GET请求
<form action="http://abcdef.com/myPath" method="GET"><input type="text" name="userId"><input type="text" name="classId"><input type="submit" value="提交">
</form>
点击”提交“按钮,此时就会把构造出HTTP请求并发送出去
构造的HTTP请求:
由于我们的服务器的地址是 随便写的,因此无法获取到正确的HTTP响应
2)发送POST请求
<form action="http://abcdef.com/myPath" method="GET"> <input type="text"name="userId"><input type="text"name="classId"><input type="submit"value="提交">
</form>
构造的HTTP请求:
主要的区别:
- method从GET变成了POST
- 数据从query string移动到了body中
5、通过ajax构造HTTP请求
ajax,Asynchronous Javascript Adng XML,是2005年提出的一种JavaScript给服务器发送HTTP请求的方式
特点是可以不需要刷新页面/页面跳转就能进行数据传输
在JavaScript中可以通过ajax的方式构造HTTP请求
1)引入jquery库
点击链接获取jquery库,选择min版本
可以直接复制此min链接打开,若是下图效果,则证明此链接是可用的
2)编写代码
①发送get请求
<body><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script> <script>$.ajax({type:'get',url:'https://www.sogou.com/abc.html',success:function(body){console.log(body);}});</script>
</body>
请求成功:
响应 404 Not Found:
②发送POST请求
<body><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script> <script>let body={key1:1,key2:2};$.ajax({type:'post',contentType:'application/json',data:JSON.stringify(body),url:'https://www.sogou.com/abc.html',success:function(body){console.log(body);}});</script>
</body>
6、HTTP下发生的运营商劫持
通过HTTP传输的数据在传输过程中是以明文形式进行传输的,没有进行加密处理。这使得HTTP传输的数据容易受到窃听和篡改的风险。比如下面的运营商劫持:
由于我们通过网络传输的任何的数据包都会经过运营商的网络设备(路由器、交换机等),那么运营商的网络设备就可以解析出你传输的数据内容,并进行篡改
比如下载天天动听,点击下载按钮,其实就是在给服务器发送了一个HTTP请求,获取到的HTTP响应其实就包含了该APP的下载链接。运营商劫持后就发现这个请求是要下载天天动听,那么就自动的把交给用户的响应给篡改成”QQ浏览器“的下载地址了
未被劫持的效果:
已被劫持的效果,要下载天天动听的给下载成QQ浏览器了:
五、HTTPS
HTTPS使用了SSL/TLS协议对数据进行加密,因此在传输过程中,数据是以加密形式传输的,可以有效防止窃听和篡改。
加密是什么?
- 加密就是把明文(要传输的信息)进行一系列变换,生成密文
- 解密就是把密文再进行一系列变换,还原成明文
在这个加密和解密的过程中,往往需要一个或者多个中间的密钥,辅助进行这个过程
加密的方式有很多,但是整体上可以分为两大类:对称密钥和非对称密钥
工作过程
1、引入对称加密
对称加密其实就是通过同一个”密钥“把明文加密成密文,并且也能把密文解密成明文
一个简单的对称加密,按位异或:
假设明文a=1234,密钥 key=8888,则加密a^key得到的密文b为9834,然后针对密文9834再次进行运算b^key,得到的就是原来的明文1234(对于字符串的对称加密也是同理,每一个字符都可以表示成一个数字)。
当然,按位异或只是最简单的对称加密,HTTPS中并不是使用按位异或。
引入对称密钥后即使数据被截获,由于黑客不知道密钥是啥,因此就无法进行解密,也就不知道请求的真实内容是啥了
但事情没这么简单,服务器同一时刻其实是给很多客户端提供服务的。这么多客户端,每个人用的密钥都必须是不同的(如果是相同的密钥就太容易扩散了,黑客也就能拿到了)。因此服务器就需要维护每个客户端和每个密钥之间的关联关系。
比较理想的做法就是能在客户端和服务器建立联系时,双方协商确定这次的密钥
但是如果直接把密钥明文传输,那么黑客也就能获得密钥了,此时后续的加密操作就形同虚设了。
因此密钥的传输也必须加密传输,但是要想对密钥进行对称加密,就仍然需要先协商确定一个”密钥的密钥“。这就成了”先有鸡还是先有蛋“的问题了。此时密钥的传输再用对称加密就行不通了。
2、引入非对称加密
非对称加密算法使用一对密钥来进行加密和解密,分别是公钥和私钥。
1)公钥和私钥
- 公钥: 公钥是公开的,用于加密数据。任何人都可以使用公钥来加密数据。
- 私钥: 私钥是保密的,用于解密数据。只有私钥的持有者可以使用私钥来解密数据
在下面这个场景中,锁就相当于公钥,钥匙就相当于私钥。
公钥给谁都行,不怕泄露(用于加密数据);但是私钥只有小女孩持有(用于解密数据)
2)加密过程
- 当客户端和服务器建立HTTPS连接时,服务器会将自己的公钥发送给客户端。
- 客户端使用服务器的公钥来加密一个对称密钥(用于后续数据传输的加密和解密),然后将加密后的对称密钥发送给服务器。
- 服务器使用自己的私钥来解密客户端发送的对称密钥。
- 之后的数据传输过程中,双方使用这个对称密钥来加密和解密数据,保证数据的安全传输 (该对称密钥只有客户端和服务器两个主机知道 , 其他主机/ 设备不知道密钥,即使截获数据也没有意义),同时又提高效率(对称加密的效率比非对称加密高很多)
上面我们提到,当客户端和服务器建立HTTPS连接时,服务器会将自己的公钥发送给客户端。那么问题来了,客户端如何获取到公钥呢?又如何确定这个公钥不是黑客伪造的呢?
3、引入证书
客户端获取服务器的公钥通常是通过数字证书来实现的。数字证书是由权威的证书颁发机构(CA)签发的,用于证明公钥的真实性和服务器身份的合法性。
获取公钥
1)服务器获取数字证书:服务器在建立HTTPS连接之前,会向证书颁发机构申请数字证书。证书包含了服务器的公钥以及该网站的相关信息,同时由证书颁发机构用其私钥进行数字签名。
2)服务器发送数字证书:当客户端向服务器发起HTTPS连接时,服务器会将自己的数字证书发送给客户端。
3)客户端验证数字证书:客户端收到服务器的数字证书后,会使用预先内置的证书颁发机构的公钥来验证数字签名,确保证书的合法性和真实性。
- 判定证书的有效期是否有效
- 判断证书的发布机构是否受信任(操作系统已内置的受信任的证书发布机构)
- 验证证书是否被篡改:从系统中拿到该证书发布机构的公钥,对签名解密,得到一个hash值(数据摘要)设为hash1;然后计算整个证书的hash值,设为hash2,对比hash1和hash2是否相等,如果相等则说明证书没有被篡改过
4)获取公钥:如果数字证书验证通过,客户端就可以从数字证书中提取服务器的公钥,然后用这个公钥来加密数据传输的对称密钥
确保公钥的真实性
1)数字证书的验证过程保证了客户端获取的公钥是合法的,而非黑客伪造的。
2)通过证书颁发机构的数字签名,客户端可以确信所获取的公钥是由合法的证书颁发机构签发的,从而避免了被伪造公钥的风险。
因此,通过数字证书和证书颁发机构的数字签名,客户端可以安全地获取并验证服务器的公钥,确保了HTTPS连接的安全性和可信度。
数据摘要/签名
比如在工作中经常会涉及到的”报销“,你拿着发票想报销需要领导批准,但是领导又不和你一起去找财务,就给你签个字就行了,财务见到领导的签字,就可以批准了。
不同的人”签名“的差别会很大,使用签名就可以一定程度上的区分出某个特定的人。
类似的,针对一段数据(比如一个字符串),也可以通过一些特定的算法对这个字符串生成一个”签名“,并保证不同的数据生成的”签名“差别很大。这样使用的签名就可以一定程度上区分不同的数据。
常见的生成签名的算法有:MD5和SHA系列
以MD5为例,MD5的特点:
- 定长:无论多长的字符串计算出来的MD5值都是固定长度
- 分散:源字符串只要改变一点点,最终得到的MD5值都会差别很大
- 不可逆:通过源字符串生成MD5很容易,但是通过MD5还原成原串理论上不可能的
正因为MD5有这样的特性,我们可以认为如果两个字符串的MD5值相同,则认为这两个字符串相同,这样的签名就可以一定程度上区分不同的数据。
判定证书的篡改过程
这个就像我们生活中的判定证件是否伪造这种情况。
假设我们的证书只是一个简单的字符串hello,对于这个字符串计算hash值(比如MD5),结果为BC4B2A76B9719D91;如果hello中任意字符被篡改了,比如改成了hella,那么计算的MD5值就会变化很大,为BDBD6F51F2FD8。
然后我们可以把这个字符串hello和哈希值BC4B2A76B9719D91从服务器返回给客户端,此时客户端如何验证hello是否被篡改过?
那么就只要计算hello的哈希值,看看是不是BC4B2A76B9719D91即可。
但是还有个问题,如果黑客把hello篡改了,同时也把哈希值重新计算下发给客户端,客户端就分辨不出来了。
所以被传输的哈希值不能传输明文,需要传输密文
这个哈希值在服务器通过另外一个私钥加密(这个私钥是申请证书的时候,证书发布机构给服务器的,不是客户端和服务器传输对私密钥的私钥)
然后客户端通过操作系统里已经存的了的证书发布机构的公钥进行解密,还原出原始的哈希值进行校验
完整流程
总结
HTTP工作过程中涉及到的密钥有3组:
第一组(非对称加密):用于校验证书是否被篡改。服务器持有私钥(私钥在注册证书时获得),客户端持有公钥(操作系统包含了可信任的CA认证机构有哪些,同时持有对应的公钥)。服务器使用这个私钥对证书签名进行加密。客户端通过这个公钥解密获取到证书的签名,从而校验证书内容是否被篡改过
第二组(非对称加密):用于协商生成对称加密的密钥。服务器生成这组私钥-公钥对,然后通过证书把公钥传递给客户端。然后客户端用这个公钥给生成的对称加密的密钥加密,传输给服务器,服务器通过私钥解密获取到对称加密密钥
第三组(对称加密):客户端和服务器后续传输的数据都通过这个对称密钥加密解密
其实一切的关键都是围绕这个对称加密的密钥,其他的机制都是辅助这个密钥工作的
- 第二组非对称加密的密钥是为了让客户端把这个对称密钥传给客户端
- 第一组非对称加密的密钥是为了让客户端拿到第二组非对称加密的公钥
六、Tomcat
Tomcat 是一个HTTP服务器,前面我们已经学习了HTTP协议,知道了HTTP协议就是HTTP客户端和HTTP服务器之间的交互数据的格式。同时也通过ajax和Java Socket分别构造了HTTP客户端。HTTP服务器我们也同样通过Java Socket来实现,而Tomcat就是基于Java实现的一个开源免费,也是被广泛使用的HTTP服务器。