目录
1. http相关概念
1.1 什么是http
- http(全称为"超文本传输协议")是一种应用非常广泛的应用层协议.
1.2 诞生与历史
http诞生与1991年,目前已经发展为了追主流的应用层协议.虽然现在http协议已经更新到了3.0版本,但是现在市面上还是以使用1.1版本为主.
http往往是基于传输层协议tcp协议实现的(除http3.0版本协议基于udp除外).
1.3 应用场景与工作过程
- 应用场景
- 网页与服务器交互
- 手机客户端与服务器交互
[注意] 在实际开发中,不一定直接用http协议,大概率使用的https协议,https协议本质上还是http协议但是引入了加密层,保证了一定的安全性.
- 工作过程
http协议是典型的一问一答模式的协议.即请求和响应都是一一对应的.
当我们在浏览器中输⼊⼀个"网址",此时浏览器就会给对应的服务器发送⼀个http请求.对方服务器收到这个请求之后,经过计算处理,就会返回⼀个http响应.
2. http协议格式
http协议是一个文本格式的协议,我们必须通过一些抓包工具来获取到网络上的http请求和响应来理解http的格式.
2.1 抓包工具的使用
抓包工具的作用就是能够把网络上传输的http数据获取到,并显示出来.抓包工具有很多.
- 常见抓包工具
- 浏览器自带抓包工具:操作不方便
- wireshark:功能非常强大的抓包工具,不经可以抓取http,还可以抓取tcp,udp,以太网等其他协议的数据.但是他强大的功能换来的是他复杂的操作成本.
- fiddle:是一种专门抓取http的抓包工具,使用起来比较方便.我们使用这个
-
fiddle安装
下载地址:https://www.telerik.com/fiddler- 选择classic版,下载用途和国家随便选择,邮箱填写自己常用的就可以.
- 下载好之后,一路next即可.
- 选择classic版,下载用途和国家随便选择,邮箱填写自己常用的就可以.
-
fiddle使用介绍
- 左侧窗口显示的是所有的http请求与响应.可以点击任意一个查看详情.
- 右侧上方显示的是http请求的报文内容,切换到raw标签页可以看到详细的数据格式.也就是http请求的原始数据.
- 右侧下方显示的是http响应的报文内容,切换到raw标签页可以看到详细的数据格式.
2.2 抓包工具的原理
fiddle相当于一个"代理".其实就是浏览器找了个跑腿的.此时fiddle就是一个代理程序.
浏览器访问sogou.com时,就会把http请求先发给fiddler,fiddler再把请求转发给sogou的服务器.当sogou服务器返回数据时,fiddler拿到返回数据,再把数据交给浏览器.因此fiddler对于浏览器和sogou服务器之间交互的数据细节,都是非常清楚的.
[注意]
- 代理程序 != 抓包工具,代理程序不仅仅有抓包工具一种,还有其他的类型的代理程序,例如fq要用到的一些加速器.
- 代理程序之间会冲突,若要抓包,确保其他代理程序是关闭的状态.
- 代理程序可以分为两种角色:
- 正向代理:帮客户端,或者是浏览器跑腿
- 反向代理:帮服务器跑腿
2.3 抓包结果分析(协议格式分析,面试重点)
以下是一个http请求/响应的抓包结果.
2.3.1 http请求
- 首行: [方法] + [url] + [版本],中间用空格隔开
- 方法:即请求方法,描述的是这个请求要干什么.对应的是首行的get.
- url:请求对方的网址.对应的是上面的https://ntp.msn.cn/edge/ntp?locale=zh-cn&title=%e6%96%b0%e5%bb%ba%e6%a0%87%e7%ad%be%e9%a1%b5&dsp=1&sp=%e5%bf%85%e5%ba%94&prerender=1&pc=cnnddb&adppc=edgestart
- 版本:http协议版本,对应的是上面的http/1.1
- header:请求报头,其中是键值对的形式,使用冒号分割键值对,每组键值对之间用\n分割,遇到第一个空行表示header部分结束.
注意,这里是第一个空行就结束,剩余的空行属于正文的内容.
- body: 正文,空行后面的内容都是body.相当于我们之前谈到的tcp与ip的载荷部分,内容是任意的,不仅仅包含html数据.body允许为空字符串.如果body存在,则在header中会有⼀个content-length属性来标识body的长度.
2.3.2 http响应
- 首行: [版本号] + [状态码] + [状态码解释],中间用空格隔开
- 版本号: http协议的版本号,对应上面的http/1.1
- 状态码与状态码解释: 表示这次响应是否成功,上面的200 ok表示的是本次响应返回成功.后面我们还会介绍到其他的状态.
- header:响应报头,其中是键值对的形式,使用冒号分割键值对,每组键值对之间用\n分割,遇到第一个空行表示header部分结束.
- body: 正文,body允许为空字符串.如果body存在,则在header中会有⼀个content-length属性来标识body的长度;如果服务器返回了⼀个html页面,那么html页面内容就是在body中.
2.3.3 协议格式的总结
2.4 http请求详解
2.4.1 url
- url基本格式
平时我们俗称的"网址"其实就是说的url(uniform resource locator统一资源定位符).下面我们来拿一个具体的url来解释url都有哪些部分构成.
https://editor.csdn.net/md?not_checkout=1&spm=1015.2103.3001.8066&articleid=139480272
- https:协议方案名,常见的有https与http.描述的是接下来url要干什么.当然也有其他的类型.(例如我们在之前jdbc编程的时候,使用的是jdbc:mysql)
- user:pass:登录信息,现在的网站一般会通过登录页面来验证,一般不通过url的方式,这个部分经常省略.
- editor.csdn.net:服务器ip地址,也叫"域名",用来确定访问的主机,我们在上一篇博客中提到过.其中域名会通过dns服务器解析为一个具体的ip地址.
- 端口号: 用来确定访问主机上的哪个程序,上面的url中端口号被省略,当省略端口号的时候,浏览器会根据协议类型自动决定使用哪个端口.例如http的默认端口是80,https是443.
- /md:带层次的文件路径.确定访问程序中的哪个资源.
- 通过ip地址,端口号,文件路径,我们就可以确定互联网上的唯一一个资源.
- not_checkout=1&spm=1015.2103.3001.8066&articleid=139480272:查询字符串(query string),表示的是一些参数,通过参数把客户端想要传给服务器的数据告知过去.它本质上一个键值对的结构,键值对之间用&符号分割,键和值之间用=分割.
- 片段标识: 次url中省略了片段标识,用于区分页面中的不同部分,作用类似与目录.可以用于页面内的跳转.
- url encode
像/?:等这样的字符,已经被url当做特殊意义理解了.因此这些字符不能随意出现.如果此时query string中,value的一部分也出现了类似的这些符号,就会使得解析出问题,所以我们对url引入了encode机制.(针对键值对中的value进行转义)
转义的规则如下:将要转码的字符转换为16进制,(如果是字符,就是acsii码值,如果是汉字,就是utf8)之后在每个字符的16进制的前面加上%,编码成%xy的形式.
例如:https://www.baidu.com/s?wd=%e8%9b%8b%e7%b3%95&rsv_spt=1&rsv_iqid=0x9cd7e614000a78b0&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&tn=67074732_6_dg&rsv_dl=tb&rsv_enter=1&rsv_sug3=7&rsv_sug1=4&rsv_sug7=100&rsv_sug2=0&rsv_btype=i&prefixsug=%25e8%259b%258b%25e7%25b3%2595&rsp=5&inputt=2189&rsv_sug4=2189
其中的好多百分号加上16进制的数据就是一个个被encode之后的查询字符串的value.
2.4.2 认识"方法"
方法,描述的是发送请求的意图,描述的是请求要干什么,也就是请求的"语义".
其中用的最多的只有两个:一个是get,一个是post.实际上这两个方法并没有明确的界限.get通常会搭配query string传输,而不是body.相反,post通常会搭配body传输,而不是query string.但是有时候也不一定.
- get方法
get是最常用的http方法,常用于获取服务器上的某个资源.那么如何构造get方法呢?- 在浏览器中共直接输入url,此时浏览器会发出一个get请求.
- 另外,html中的link,img,script等标签,也会触发get请求,这些标签会有url作为属性.
- 表单
<form>
也可以构造get方法. - 使用javascript中的ajax也可以构造get.
- post方法
多用于提交用户输入的数据给服务器(比如登录页面).那么post方法是如何构造的呢?- 通过html的
<form>
标签可以构造post请求. - 或者使用javascript的ajax也可以构造post请求.
- 通过html的
- (经典面试题)get与post有何区别?
- get何post其实本质上没有什么区别.get的应用场景,post也可以.post的应用场景,get也可以.
- get从语义上来说,通常是用来"获取数据",post从语义上来说,是用来"提交数据"的.
- get在传递数据的时候,通常用query string,post在传递数据的时候,通常使用body.
- 服务器对于get请求的设计,经常是"幂等"的,而post不是.
何为幂等?通俗一点讲.
就是每次访问的结果都一样.举个例子来说明一下:一头牛,今天草,今天挤奶,明天吃草,明天挤出来的还是奶.这是幂等的情况.还是一头牛,今天吃草,今天挤奶,明天吃草,明天挤出来的是翔.这就是不幂等的情况. - get请求的结果可以被缓存,可以被收藏夹收藏,(比如一个网站,通过get方法获取图片,浏览器可以缓存这些图片,下次访问的时候,直接从缓存中来读取)但是post一般不行.
- 但是关于上面这个问题,有很多典型的错误的说法.
- post安全,get不安全
关于安全不安全这个问题,取决于加密操作,保证黑客在对网络请求抓包之后不会对密码进破解,不是说写在query string中就安全,写在body中就不安全. - get传输的数据有限,post传输的数量没有限制.
这样的情况只出现于上古时期的ie浏览器,但现在好多get方法的请求也没有数据多少的限制.
而且在http的标准中也明确说明了一句话,针对get的url长度不做限制,也就是get请求用来传输数据的query string长度没有限制. - get只能传输文本,post可以传输文本,也可以传输二进制数据.
url的query string中提供了urlencode机制,二进制数据可以进行encode得到转义,并进行传输.虽然post可以直接传输二进制,但是很多时候,可以转义之后通过文本的方式来传输.
- post安全,get不安全
2.4.3 请求报头
- host: 表示服务器主机上的地址和端口,一般和url中的ip和端口一样.
- content-length(正文长度)
表示body的长度,一旦有body,就要知道body有多长,才可以知道从哪里到哪里是一个完整的http请求.
此时就是我们经常见到的"粘包问题",在没有body的情况下,比如get方法的请求,通过query string来传递信息,这时候,区分一个完整的http请求就是通过host之后的空行来区分的,但是像post这种通过body来传递数据的请求,就需要通过在host中引入content-length来找到body的开始位置与结束位置,从而区分一个完整的http请求. - content-type(正文数据格式)
表示的是请求body中的数据格式.比如图片,视频,音频这些不同的数据.浏览器和服务器针对不同的数据格式会有不同的处理方式.
常见的类型有以下几个:
- application/x-www-form-urlencoded:form表单提交的数据格式
title=test&content=hello
- multipart/form-data:form表单提交的数据格式(在form标签中加上enctyped=“multipart/form-data” .通常⽤于提交图⽚/⽂件.
content-type:multipart/form-data; boundary=----webkitformboundaryrgkcby7qhfd3trw
------webkitformboundaryrgkcby7qhfd3trwa
content-disposition: form-data; name="text"
title
------webkitformboundaryrgkcby7qhfd3trwa
content-disposition: form-data; name="file"; filename="chrome.png"
content-type: image/png
png ... content of chrome.png ...
------webkitformboundaryrgkcby7qhfd3trwa--
- application/json:数据为json格式.
{"username":"123456789","password":"xxxx","code":"jw7l","uuid":"d110a05ccde64b16"}
-
user-agent(简称ua)
表示浏览器/操作系统的属性.例如:
mozilla/5.0 (windows nt 10.0; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/125.0.0.0 safari/537.36 edg/125.0.0.0
-
mozilla:是一个开源组织.
-
windows nt 10.0; win64; x64:表示的是操作系统的信息.其中,
windows nt 10.0
表示操作系统的版本,win64; x64
表示次操作系统是64位操作系统. -
applewebkit/537.36:表示的是浏览器的内核.
-
khtml, like gecko) chrome/125.0.0.0 safari/537.36 edg/125.0.0.0: 浏览器的其他信息.
-
那么ua是用来干什么用的呢?
现在的ua,最主要的作用是用来区分电脑手机和平板,比较老的网站用的是url来区分,区分这这些的作用就决定着返回的页面是怎样的外观,如果是电脑,返回的就是一个大页面,如果是手机平板,返回的就是一个小页面.但是最大的问题就是,使用ua来区分设备的不同,就要维护好几种不同设备的代码,这时候我们就引入了响应式布局,我们只写一套代码,通过前端的一些代码,可以根据设备的不同尺寸设置不同的样式去适应设备.
-
-
referer
表示的是这个页面是从哪个页面跳转过来的,例如:
referer: https://cn.bing.com/
表示的是这个页面是从bing的搜索引擎的主页跳转过来的.
[注意] 如果直接在浏览器中输入url,或者直接在收藏夹中共访问页面的时候,是没有referer的.因为没有触发页面的跳转.
-
cookie(重点面试题)
cookie中的内容和url中的query string内容类似,都是键值对内容,它们都是程序员自定义的.每个键值对之间用";“隔开,键和值之间用”="隔开.
- cookie是浏览器本地存储的一种机制,cookie本质上可以在客户端的硬盘上持久化保存的.是浏览器给网页的一种能够持久化存储数据的机制.
- 有的网站,需要在客户端这边存储一些必要的信息,希望可以持久化存储,于是浏览器就给网页提供了cookie,是浏览器对于硬盘的操作做了一些特殊的封装,相当于提供了一个或者一组特殊的文件,并且内容只能是键值对.
- 那么cookie是具体如何保存的呢?
浏览器会针对不同的域名,每个网站都有自己的cookie文件保存在硬盘中. - cookie从哪里来?
cookie中的数据,来自于服务器(服务器返回给浏览器的数据),访问网站的时候,网站的服务器会返回http响应,在http响应中,会包含set-cookie这样的header,它就会把一些键值对保存到浏览器的cookie中.cookie保存到浏览器之后,后续浏览器访问该网站的时候,就会在请求的header中,把之前保存的键值对都带入进去,在返回给服务器. - 那么问题又来了,为什么还要返回给服务器?
这是因为cookie可以使客户端存储一些必要的"配置信息",从而让服务器对于用户提供的服务更加"个性化".
和上面剪头发是相同的道理,客户端也不止有一个,每个客户端都会有自己的偏好,此时就需要让每个客户端保存这样的数据,之后就可以通过cookie随时把这样的信息返回给服务器.例如:浏览器的夜间模式和白日模式,一次设置好了之后,下次再打开服务器的时候,浏览器的颜色模式不会改变.
- cookie自动登录
cookie中虽然有很多的键值对都是程序员自定义的,但是往往会有一个特殊的键值对,用来标识用户的身份信息.
- 首先在获取登录页面与返回登录登录页面的html的过程中不包含任何的cookie.
- 在用户输入用户名和密码之后,这时候用户名和密码就会交给服务器,验证它们的正确性,在确认正确之后,就会创建会话(session),(会话可以理解为一个类,其中类中具体包含什么,要看业务逻辑,但是其中一定有sessionid,也就是令牌)并把sessionid返回给浏览器,这个sessionid存在于响应报文header中的set-cookie中,我们也可以把他叫做"令牌",令牌中存储的是一个字符串,类似于"身份标识",不会存储太多的信息,在浏览器收到sessionid之后,就会把id存储在硬盘中,即创建了cookie.
- 在之后客户端要访问该域名下的其他页面的时候,就可以把sessionid交给服务器,服务器获取到sessionid之后,就可以根据这个值,知道用户的详细信息.也就是直接通过之前创建的sessionid的cookie就可以访问到,无需再次登录.
2.5 http响应详解
2.5.1 状态码
状态码表示访问一个页面的结果,是访问成功,还是失败,还是其他的一些情况…其中每一个状态码都有一个或者一组单词来描述.
以下为常见到的状态码.
- 200 ok
这是一个最常见到的状态码,表示访问一个页面成功. - 404 not found
没有找到资源,客户端请求的资源(与url唯一资源定位符有关)在服务器中不存在.
例如:
我们访问b站的一些内容.如果输入的url中的资源在服务器中存在,就可以正常访问到
如果我们把文件路径稍微修改,就会发现,找不到资源.
- 403 forbidden(被禁止的 .adj)
表示拒绝访问.有的页面通常需要用户有一些特定的权限才可以访问到(登录之后才可以访问).如果出现了403,就说明访问权限不足.
例如:访问码云的私有仓库,如果在不登录的情况下,就会出现403.
- 405 method not allowed
前面在http请求中,我们学习了许多方法,但是访问对方的服务器不一定支持所有的方法,或者不允许用户使用一些其他的方法,此时就会出现405. - 500 internal server error
服务器内部出现了错误,也就是服务器代码中的bug.
我们平时常用的网站很少出现500,这是因为软件产品必须保证"高可用",核心思想就是:冗余.服务器不一定是一台,而是很多台,一台服务器挂了,不会有很大的影响,还有其他的机器在撑着. - 504 gateway timeout
网关服务器响应超时,也就是访问服务器的入口响应超时.
当服务器负载比较大的时候,服务器处理单条请求的时候消耗的时间就会很长,就可能会导致出现超时的情况.
- 302 move temporarily
临时重定向.在访问某个旧地址的时候,自动跳转到新地址上.在登录的页面中,经常会见到302,用于实现登录之后自动跳转到主页.
响应报文中的header中会包含一个location字段,表示要跳转到哪个页面.
- 301 move permanently
永久重定向.访问的旧地址和新地址之间的映射关系固定.此时浏览器会把这样的结果缓存下来.后续再次访问旧地址的时候,浏览器可以直接构造新地址请求,不必在通过旧地址跳转到新的地址上.减少了一次http访问.
永久重定向与临时重定向最大的区别就是是否需要从旧地址跳转到过来.
- 状态码可以根据第一位的数字对他表示的含义进行分类
2.5.2 响应报头
响应报头的基本格式和请求报头基本一致.
类似于content-length,content-type也和请求基本一致.
- 响应中content-type的常见取值:
• text/html :body数据格式是html
• text/css :body数据格式是css
• application/javascript :body数据格式是javascript
• application/json :body数据格式是json
2. https协议
2.1 什么是https
https也是一个应用层协议.是在http的基础上引入了一个加密层.所谓https就是http+ssl,这个ssl就是所谓的安全相关的协议.
2.2 什么是加密操作
加密就是把明文(要传输的信息)进行⼀系列变换,生成密文.
解密就是把密文再进行一系列变换,还原成明文.
密文和明文之间需要通过密钥来进行加密和解密.
2.3 https的工作过程(面试重点)
说https的工作过程,也就是在谈论https如何保证数据的安全.
既然要保证数据的安全,我们就要进行加密操作.加密的方式有很多,但是整体可以分为两大类:对称加密和非对称加密.
2.3.1 对称加密
对称加密就是通过同一个"密钥",把明文加密为密文,并且也可以把密文解密为明文.这种加密的方式速度比较快.引入了对称加密之后,即使数据被截获,黑客不知道密钥是什么,此时截获数据也没有用.
但事情没这么简单.服务器同⼀时刻其实是给很多客户端提供服务的.这么多客户端,每个人用的密钥都必须是不同的(如果是相同那密钥就太容易扩散了,黑客就也能拿到了).因此服务器就需要维护每个客户端和每个密钥之间的关联关系,这也是个很麻烦的事情.
比较理想的做法就是,在客户端和服务器建立连接的时候,双方协商决定这次的密钥是什么.
但是如果直接把密钥明⽂传输,那么黑客也就能获得密钥了,此时后续的加密操作就形同虚设了.
因此密钥的传输也必须加密传输!
但是要想对密钥进行对称加密,就仍然需要先协商确定⼀个"密钥的密钥".这就成了"先有鸡还是先有蛋"的问题了.此时密钥的传输再用对称加密就行不通了,就陷入了死循环中.
就需要引入非对称加密.
2.3.2 非对称加密
[注意] 这种加密方式不是针对数据进行加密,而是针对对称密钥进行加密.
-
相关概念
非对称加密要用到两个密钥,一个叫做"公钥",一个叫做"私钥" .
公钥和私钥是配对的,最大的缺点就是运算速度非常慢,比对称加密要慢很多.
其中加密和解密所要使用的密钥正好相反.-
通过公钥对明文加密,变成密文
-
通过私钥对密文解密,变成明文
也可以反着用
-
通过私钥对明文加密,变成密文
-
通过公钥对密文解密,变成明文
-
-
加密流程
- 当客户端连接上服务器是,服务器就把自己的公钥告诉了客户端,同时生成私钥.公钥会告诉所有客户端,私钥自己留好,不告诉任何人.
- 客户端在本地生成对称密钥,通过服务器返回的对对称密钥使用公钥加密,发送给服务器.
- 由于中间的网络设置没有私钥,即使截获了数据,也无法还原出内部原文.
- 服务器通过私钥解密,还原出客户端发送的对称密钥,使用对称密钥解密数据.并且使用这个对称密钥加密给客户端返回的响应数据.
虽然非对称加密看上去天衣无缝,但是还是会有一些漏洞.问题就在于,客户端获取到的公钥是否正确?客户端如何知道这个公钥是不是黑客伪造的?
-
中间人攻击
黑客可以使用中间人攻击,获取到对称密钥.就是在客户端面前冒充服务器,在服务器面前冒充客户端.
中间人攻击的流程如下:
- 关键一步就是在中间网络设备发送公钥的时候,使用的是黑客自己创建的公钥,之后黑客便可以轻轻松松拿着自己生成的私钥进行解密.
- 之后为了哄骗服务器,又再次使用服务器返回的pub公钥进行了一次加密.
2.3.3 证书
为了防止上述的情况发生,我们引入了第三方公证机构.即引入证书.证书就如身份证,证明服务器公钥的权威性.
- 证书内容
证书可以理解为是一个结构化的字符串,里面包含了一下信息:
证书发布机构,证书有效期,公钥,证书所有者,数字签名.
这里的数字签名就相当于加密之后的校验和,基于非对称的方式进行加密,由公证机构生成签名与非对称密钥.证书整体校验和通过公证机构私钥进行加密,就形成了数字签名. - 证书如何保障安全
[注意]
- 用来给数字签名解密的公钥不是通过网络传输的,这样仍然会被黑客劫持,而是在os装入主机的时候,就已经自带了公证机构的证书.
- 此时的私钥和公钥就不是由服务器生成了,而是由第三方公证机构生成,在服务器和客户端进行通信的时候全部通过证书来实现,其中数字签名经过了公证处的私钥加密.
- 通过上述两点,就巧妙的绕过了黑客对于公钥和私钥的干预.
- 如果黑客入侵干预
- 如果黑客修改了证书中的公钥,未修改签名.
此时客户端在进行校验的时候,发自己从os调用的公钥解密出的数字签名和证书上提供的公钥解密出的数字签名结果对不上.则判定证书无效. - 黑客自己重新计算校验和,重新加密得到数字签名,并生成自己的私钥和公钥,并修改了证书上的公钥.
客户端在收到数据之后,拿着公证处的公钥解密,公证处与黑客的私钥不配对,解密失败.判定证书无效.
- 如果黑客修改了证书中的公钥,未修改签名.
发表评论