详解http协议和https协议
详解http协议和https协议
虽然我们说, 应用层协议是我们程序猿自己定的.
但实际上, 已经有大佬们定义了一些现成的, 又非常好用的应用层协议, 供我们直接参考使用. HTTP(超文本传输协议)就是其中之一.
http协议:
http协议的介绍:
HTTP(Hyper Text Transfer Protocol)协议又叫做超文本传输协议,是一个简单的请求-响应协议,HTTP通常运行在TCP之上。
- 在编写网络通信代码时,我们可以自己进行协议的定制,但实际有很多优秀的工程师早就已经写出了许多非常成熟的应用层协议,其中最典型的就是HTTP协议。
URL的组成:
平时我们俗称的 “网址” 其实就是说的 URL。
ip会标识一台网络主机,看到”/“就知道这台网络主机用的是Linux系统。使用url就可以通过浏览器请求这台网络主机的服务器,从指定的文件路径下找到用户请求的文件返回给用户。
urlencode和urldecode
像 / ? : 等这样的字符, 已经被url当做特殊意义理解了. 因此这些字符不能随意出现.
比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义.
转义的规则如下:
将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式
例如:
“+” 被转义成了 “%2B”
urldecode就是urlencode的逆过程;
UrlEncode编码/UrlDecode解码 - 站长工具 (chinaz.com)
http的请求方法、状态码及状态码描述、常见的响应报头
HTTP协议的请求格式
HTTP请求由如下四部分构成:(每行以\r\n结尾)
请求行:[请求方法] + [url(一般省略了域名和端口,只有路径)] + [http版本]。ps:http协议请求时大小写是忽略的,例如请求行的 GET / HTTP/1.1 和get / http/1.1都一样
- 请求报头:请求的属性,这些属性都是以 key: value的形式按行陈列的(: 和value中间有空格)
- 空行:因为只包含了一个 \r\n,用于做分隔符,把报头和有效载荷分离
- 请求正文:请求正文允许为空字符串,如果请求正文存在,则在请求报头中会有一个Content-Length属性来标识请求正文的长度
其中,前面三部分是一般是HTTP协议自带的,是由HTTP协议自行设置的,而请求正文一般是用户的相关信息或数据,如果用户在请求时没有信息要上传给服务器,此时请求正文就为空字符串。
GET和POST方法提交参数的区别:
客户端进行数据提交时,是通过前端的from表单提交的,浏览器会将from表单中的内容转换为GET/POST方法。
1、GET方法通过URL传递参数。例如http://ip:port/XXX/YY?key1=value1&key2=value2。像百度的搜索就是用的GET方法。GET方法通过url传递参数,参数注定不能太大,例如上传视频等巨长的二进制文件就不适合用GET了。
2、POST提交参数通过http请求正文提交参数。请求正文可以很大,可以提交视频等巨长的文件。
3、POST方法提交参数,用户是看不到的,私密性更高,而GET方法不私密。私密性不等于安全性,POST方法和GET方法其实都不安全!(http请求都是可以被抓到的,想要安全必须加密,使用https协议)
注意:如果用的是GET方法,需要对url进行额外的处理,例如/test.py?key1=value1&key2=value2,需要拆解出其中的路径(_path),即”test.py”。问号右侧则是参数(_parm)。
如何将HTTP请求的报头与有效载荷进行分离?
当应用层收到一个HTTP请求时,它必须想办法将HTTP的报头与有效载荷进行分离。对于HTTP请求来讲,这里的请求行和请求报头就是HTTP的报头信息,而这里的请求正文实际就是HTTP的有效载荷。
如果将HTTP请求想象成一个大的线性结构,此时每行的内容都是用 \r\n 隔开的,因此在读取过程中,如果连续读取到了两个 \r\n ,就说明已经将报头读取完毕了,后面剩下的就是有效载荷了。
HTTP协议响应协议格式:
HTTP响应由以下四部分组成:(也是每行以 \r\n 结尾)
- 状态行:[http版本 (http/1.1) ]+[状态码 (例如404报错,200代表OK) ]+[状态码描述 (例如404对应的”Not Found”描述) ]
- 响应报头:响应的属性,这些属性都是以key: value的形式按行陈列的。(注意:和value中间有空格)比如 Content-Type: text/html; charset=utf-8 用于表示正文是 text/html文档类型,字符集为utf-8
- 空行:因为只包含了一个 \r\n ,用与做分隔符,把报头和有效载荷分离
- 响应正文:响应正文允许为空字符串,如果响应正文存在,则响应报头中会有一个Content-Length属性来标识响应正文的长度。比如服务器返回了一个html页面,那么这个html页面的内容就是在响应正文当中的。
telnet命令远程登陆服务
我们可以使用telnet命令获取百度给我的响应:
结果如下:
获取响应正文的长度
STAT(2)
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
struct stat {
dev_t st_dev; // 包含文件的设备ID
ino_t st_ino; // inode号
mode_t st_mode; // 文件保护模式
nlink_t st_nlink; // 硬链接数
uid_t st_uid; // 文件所有者的用户ID
gid_t st_gid; // 文件所有者的组ID
dev_t st_rdev; // 设备ID(如果是特殊文件)
off_t st_size; // 总大小,以字节为单位
blksize_t st_blksize; // 文件系统I/O的块大小
blkcnt_t st_blocks; // 分配的512B块数
time_t st_atime; // 上次访问时间
time_t st_mtime; // 上次修改时间
time_t st_ctime; // 上次状态更改时间
};
用途:函数stat用于获取文件的状态信息,包括文件类型、文件大小、文件权限等。函数stat只能获取普通文件、目录、符号链接等文件的状态信息,无法获取设备文件等特殊文件的状态信息。
参数:
path:文件路径
buf:存储文件状态信息的结构体指针
返回值:函数返回值为0表示成功,-1表示失败
得到_path路径下的文件大小,单位字节:
struct stat st;
int n=stat(_path.c_str(),&st);
if(0==n)
{
_size=st.st_size;
}
else{
_size=-1;}
http状态码及状态码描述
HTTP状态码是由服务器返回给客户端的三位数字代码,用于表示客户端请求的处理状态。以下是常见的HTTP状态码及其描述:
1xx(信息性状态码):表示请求已被接收,继续处理。
2xx(成功状态码):表示请求已成功被服务器接收、理解、并接受。
- 200 OK:请求成功。
- 201 Created:请求已经被实现,资源已经被创建。
- 204 No Content:请求成功,但响应报文不含实体的主体部分。
3xx(重定向状态码):客户端发送请求,服务器返回3XX状态码和一个新的URL,客户端拿着这个新的URL再次请求服务器,这就是重定向。
- 301 Moved Permanently:永久性重定向。
- 302 Found:临时性重定向。
- 304 Not Modified:客户端已经执行了GET,但文件未变化。
- 307 Temporary Redirect:临时性重定向。
4xx(客户端错误状态码):表示客户端请求出错,服务器无法处理请求。
- 400 Bad Request:请求报文存在语法错误。
- 401 Unauthorized:未经授权,需要身份验证。
- 403 Forbidden:服务器拒绝请求。
- 404 Not Found:服务器无法找到请求的资源。(属于客户端错误,客户端请求资源在服务器不存在)
5xx(服务器错误状态码):表示服务器处理请求出错。
- 500 Internal Server Error:服务器内部错误。
- 502 Bad Gateway:网关错误。
- 503 Service Unavailable:服务器暂时无法处理请求。
- 504 Gateway Timeout:网关超时
重定向状态码
重定向就是通过各种方法将各种网络请求重新定个方向转到其它位置,此时这个服务器相当于提供了一个引路的服务。且返回的响应response报头里会携带http的响应属性Location:new url。此时就会重定向到新的url网址。
重定向又可分为临时重定向和永久重定向,其中状态码301表示的就是永久重定向,而状态码302和307表示的是临时重定向。
临时重定向:
进行临时重定向时需要用到Location字段,Location字段是HTTP报头当中的一个属性信息,该字段表明了你所要重定向到的目标网站。
我们这里要演示临时重定向,可以将HTTP响应当中的状态码改为302,然后跟上对应的状态码描述,此外,还需要在HTTP响应报头当中添加Location字段,这个Location后面跟的就是你需要重定向到的网页,比如我们这里将其设置为B站的首页
\临时重定向 VS 永久重定向:**
- 一个网站1如果临时不想被访问就用 302 暂时重定向 重定向到网站2;一个网站1如果永久不想被访问就用 301 永久重定向 重定向到网站2;
http常见的响应报头
HTTP协议常见的响应报头包括:
- Content-Type:指定响应体的MIME类型,例如text/html表示HTML文本,image/jpeg表示JPEG图片等。
- Content-Length:指定响应体的长度,单位为字节。
- Cache-Control:指定缓存控制策略,例如no-cache表示不缓存,max-age=3600表示缓存1小时等。
- Expires:指定响应过期时间,通常与Cache-Control一起使用。
- Last-Modified:指定资源的最后修改时间,用于协商缓存。
- ETag:指定资源的唯一标识符,用于协商缓存。
- Location:搭配3XX状态码使用,指定重定向的目标URL。
- Set-Cookie:指定响应中的Cookie信息。
- Server:指定服务器软件的名称和版本号。
- X-Powered-By:指定服务器使用的编程语言和框架。
http协议客户端和服务器的通信过程
以个人云服务器作服务器,浏览器作客户端,服务器打印客户端请求如图:
这个http请求可以看到请求的设备信息,如果在手机端浏览器搜索“微信下载”,浏览器将会返回手机版的微信下载网页,若在电脑浏览器搜索,将会返回电脑版的微信下载网页。
以个人云服务器作服务器,浏览器作客户端,服务器的响应格式:
Content-Type: text/html\r\n用于指示所传输的数据是HTML格式的文本。注意响应报头位置不要打成test了,这些都是设定好的,如果输错了,浏览器请求服务器时,会变成下载html文件!同样的,图片的响应报头写错了,当客户端请求图片时,同样会变成下载逻辑。
http长连接:
http请求是基于tcp协议的,而tcp是需要进行连接的。对于一个网页,可能包含多种元素,则需要发起多次连接。为了减少连接次数,需要客户端和服务器均支持长链接,建立一条连接,传输一份大的资源通过一条连接完成。
Connection: keep-alive
Connection: close
如果报头的”Connection: “显示是”keep-alive”,则代表支持长连接。
cookie
HTTP实际上是一种无状态协议,HTTP的每次请求/响应之间是没有任何关系的,但你在使用浏览器的时候发现并不是这样的。
比如当你登录一次B站后,就算你把B站关了甚至是重启电脑,当你再次打开B站时,B站并没有要求你再次输入账号和密码,这实际上是通过cookie技术实现的,点击浏览器当中锁的标志就可以看到对应网站的各种cookie数据。
这些cookie数据实际都是对应的服务器方写的,如果你将对应的某些cookie删除,那么此时可能就需要你重新进行登录认证了,因为你删除的可能正好就是你登录时所设置的cookie信息。
cookie是一种保存在客户端的小型文本文件,用于保存服务器通过Set-Cookie字段返回的数据,在下次请求服务器时通过Cookie字段将内容发送给服务器。是HTTP进行客户端状态维护的一种方式。而Set-Cookie以及Cookie字段可以包含有多条信息,也可以由多个Cookie及-Set-Cookie字段进行传输多条信息,并且cookie有生命周期,在超过生命周期后cookie将失效,对应的cookie文件将被删除。
cookie的失效时间:
Cookie的Expires属性指定了cookie的生存期,默认情况下coolie是暂时存在的,他们存储的值只在浏览器会话期间存在,当用户退出浏览器后这些值也会丢失,如果想让cookie存在一段时间,就要为expires属性设置为未来的一个过期日期。现在已经被max-age属性所取代,max-age用秒来设置cookie的生存期。当没有设定过期时间时,则退出当前会话时cookie失效
如果没有为Cookie指定失效时间,则设置的Cookie将在何时失效?
如果不设置过期时间,则表示这个cookie生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。这种生命期为浏览会话期的cookie被称为会话cookie。会话cookie一般不保存在硬盘上而是保存在内存里。
如果设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie依然有效直到超过设定的过期时间。
内存级别 vs 文件级别:
cookie就是在浏览器当中的一个小文件,文件里记录的就是用户的私有信息。cookie文件可以分为两种,一种是内存级别的cookie文件,另一种是文件级别的cookie文件。
将浏览器关掉后再打开,访问之前登录过的网站,如果需要你重新输入账号和密码,说明你之前登录时浏览器当中保存的cookie信息是内存级别的。
将浏览器关掉甚至将电脑重启再打开,访问之前登录过的网站,如果不需要你重新输入账户和密码,说明你之前登录时浏览器当中保存的cookie信息是文件级别的。
cookie的登陆策略:
因为HTTP是一种无状态协议,如果没有cookie的存在,那么每当我们要进行页面请求时都需要重新输入账号和密码进行认证,这样太麻烦了。
就比如你是爱奇艺的VIP会员,你每次点击一个VIP视频都要重新进行VIP身份认证。而HTTP不支持记录用户状态,那么我们就需要有一种独立技术来帮我们支持,这种技术目前现在已经内置到HTTP协议当中了,叫做cookie。
cookie的登陆策略如下:
当第一次登陆某网站时,客户端向服务器输入我们的用户名和密码
服务器把 cookie用户名&&密码返回给客户端(在HTTP请求中的Cookie是明文传递的)
客户端下次登录 自动携带浏览器访问该网站对应的cookie文件中的内容,这样就能保持登录
总的来说就是第一次登录时,服务器就会进行Set-Cookie的设置(Set-Cookie也是HTTP报头当中的一种属性信息)。当认证通过并在服务端进行Set-Cookie设置后,服务器在对浏览器进行HTTP响应时就会将这个Set-Cookie响应给浏览器。而浏览器收到响应后会自动提取出Set-Cookie的值,将其保存在浏览器的cookie文件当中,此时就相当于我的账号和密码信息保存在本地浏览器的cookie文件当中。
cookie的风险:
仅仅是cookie的登陆策略会存在安全隐患:
当你不小心被迫下载了木马病毒,该病毒会扫描你的浏览器当中的cookie目录,它就会把所有的cookie信息通过网络的方式传给黑客,你的cookie用户名密码可能会被盗取,黑客会拿着你的cookie去登录,更严重的是黑客会修改你的cookie密码对账号产生威胁。
因此单纯的使用cookie是非常不安全的,因为此时cookie文件当中就保存的是你的私密信息,一旦cookie文件泄漏你的隐私信息也就泄漏。
解决办法就是使用cookie + session的登陆策略。
cookie + session
例如我们打开哔哩哔哩的首页进行登录操作,哪怕用户马上把浏览器关了,短期内再次访问哔哩哔哩是不需要用户重复登录操作的。同样的,当我们在哔哩哔哩进行页面跳转时,http协议并不会记录用户信息,但是曾经的用户登录信息在页面跳转时并不会丢失。浏览器仍会记住上一次登录的信息。这就是会话保持。
其实http请求是无状态的,每次请求并不会记录它曾经请求了什么。所以会话保持不是http协议天然具备的特点,而是浏览器为了满足用户的使用需求,做了相应的工作。
用户在第一次输入账号和密码时,浏览器会进行保存(Cookie),近期再次访问同一个网站,浏览器会自动将用户信息推送给服务器。像哔哩哔哩中某些需要大会员才能观看的视频,服务器都会先获取用户信息进行身份判断,用的就是浏览器缓存的信息。这样只要用户首次输入密码,一段时间内将不用再做登录操作了。
但是本地的Cookie如果被不法分子拿到,那不是危险了,所以信息的保存是在服务器上完成的,服务器会对每个用户创建一份独有的session id,并将其返回给浏览器,浏览器存到Cookie的其实是session id。但这样只能保证原始的账号密码不会被泄漏,黑客盗取了用户的session id后仍可以非法登录,只能靠服务端的安全策略保障安全,例如账号被异地登录了,服务端察觉后只要让session id失效即可,这样异地登录将会使用户重新验证账号密码或手机或人脸信息(尽可能确保是本人),一定程度上保障了信息的安全。
服务器向客户端返回Cookie:
//写入Cookie
respHeader+="Set-Cookie: name=12345abcde; Max-Age=120\r\n";//设置Cookie响应报头,有效期2分钟
//往后,每次http请求都会自动携带曾经设置的所有Cookie,帮助服务器的鉴权行为————http会话保持
http相关工具
1、postman——能够模拟客户端浏览器的行为。
2、fiddler——一个本地抓包工具,作为http调试使用。(能够明文抓到本地的POST方法请求正文!)
所以http协议并不安全,想要安全还得看https协议…
https协议
https协议的介绍
http协议内容都是按照⽂本的⽅式明⽂进行传输,这就导致在传输过程中信息被轻易窃取、篡改。
https协议属于应用层协议之一,是在http协议的基础上引⼊了⼀个加密层。如果一方是使用https协议进行发送的,那么接收的一方也必定是https协议。https协议保障了数据在网络中的安全。我们可以根据其所绑定的端口号来区分是http协议还是https协议。
加密和解密
" class="reference-link">
加密就是把明⽂(要传输的信息)进行⼀系列变换, ⽣成密文;解密就是把密⽂再进⾏⼀系列变换, 还原成明文。
为什么需要加密和解密?
因为http的内容是明文传输的,明⽂数据会经过路由器、wifi热点、通信服务运营商、代理服务器等多个物理节点,如果信息在传输过程中被劫持,传输的内容就完全暴露了。劫持者还可以篡改传输的信息且不被对⽅察觉,这就是中间人攻击 ,所以我们才需要对信息进⾏加密。
常见的加密方式:
- 对称加密
采用单钥密码系统的加密⽅法,同⼀个密钥可以同时⽤作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密,特征:加密和解密所⽤的密钥是相同的。
• 常见对称加密算法(了解一下):DES、3DES、AES、TDEA、Blowfish、RC2等
• 特点:算法公开、计算量⼩、加密速度快、加密效率高
对称加密其实就是通过同⼀个 “密钥” , 把明⽂加密成密文, 并且也能把密⽂解密成明文。
按位异或就是⼀个简单的对称加密,不过HTTPS 中并不是使用按位异或。
- 非对称加密
需要两个密钥来进行加密和解密,这两个密钥是公开密钥(public key,简称公钥)和私有密钥(private key,简称私钥)。
• 常见非对称加密算法(了解):RSA,DSA,ECDSA
• 特点:算法强度复杂、安全性依赖于算法与密钥但是由于其算法复杂,⽽使得加密解密速度没有对称加密解密的速度快。 公钥和私钥是配对的. 最⼤的缺点就是运算速度非常慢,比对称加密要慢很多。公钥可以认为是一把锁,私钥是锁的钥匙,锁给谁都行,但是只有持有私钥的人才能打开。
• 通过公钥对明文加密, 变成密文;通过私钥对密⽂解密, 变成明⽂
当然也可以反着用:
• 通过私钥对明⽂加密, 变成密文;通过公钥对密⽂解密, 变成明⽂
数据摘要(数据指纹)
• 数字指纹(数据摘要),其基本原理是利⽤单向散列函数(Hash函数)对信息进⾏运算,⽣成⼀串固定⻓度的数字摘要。数字指纹并不是⼀种加密机制,但可以⽤来判断数据有没有被窜改,如果对数据某个地方进行小小的改动,重新生成的哈希摘要也和改动前的大不一样。
• 摘要常见算法:有MD5、SHA1、SHA256、SHA512等,算法把⽆限的映射成有限,因此可能会有碰撞(两个不同的信息,算出的摘要相同,但是概率非常低)
• 摘要特征:和加密算法的区别是,摘要严格意义不是加密,因为没有解密,只不过从摘要很难反推原信息,通常用来进行前后数据的对比,观察数据是否被修改过,也可以用于实现网盘的秒传功能、公司数据库密码存储等。
涉及到用户密码的字段,都是要加密的。一般数据库中的密码字段,长度是固定的(便于设计表结构),会将用户密码生成哈希摘要。每次用户登录时都将转换成哈希摘要与数据库的哈希摘要进行对比,所以数据库泄露也不怕。
数字签名
• 对摘要经过加密,得到的就是数字签名。签名的形成是基于非对称加密算法。
HTTPS的工作过程讨论
方案1 —— 只使用对称加密(明文传输不可取)
如果通信双方都各自持有同一个密钥X,且没有别人知道,这两方的通信安全当然是可以被保证的(除非密钥被破解)
引入对称加密之后,即使数据被截获,由于黑客不知道密钥是啥,因此就无法进行解密,也就不知道请求的真实内容是啥了。
但是上述方案有一个问题:如何做到让客户端和服务端拥有同一个密钥?服务器是同时给多个客户端提供服务的。这么多客户端,每个人用的秘钥都必须是不同的(如果是相同那密钥就太容易扩散了,黑客就也能拿到了)。因此服务器就需要维护每个客户端和每个密钥之间的关联关系,这也是个很麻烦的事情~
比较理想的做法,就是能在客户端和服务器建立连接的时候,双方协商确定这次的密钥是啥~
但是如果直接把密钥明文传输,那么黑客也就能获得密钥了~~此时后续的加密操作就形同虚设了。
因此密钥的传输也必须加密传输!
但是要想对密钥进行对称加密,就仍然需要先协商确定一个”密钥的密钥”。这就成了 “先有鸡还是先有蛋” 的问题了。此时密钥的传输再用对称加密就行不通了3
方案2 —— 只使用非对称加密(仅单向安全,不可取)
鉴于非对称加密的机制,如果服务器先把公钥以明文方式传输给浏览器,之后浏览器向服务器传数据前都先用这个公钥加密好再传,从客户端到服务器信道似乎是安全的(有安全问题),因为只有服务器有相应的私钥能解开公钥加密的数据。
上述过程中,私钥S只有服务器私有,不会暴露在公网中,即使黑客拿到了暴露在公网中的公钥和密文,但是没有私钥(只能用私钥解密),所以黑客无法对密文解密,也就保证了从客户端发送到服务端的消息目前是安全的。
如果此时服务器向客户端发消息,服务器只能用私钥进行加密(因为客户端只有公钥,私钥加密只能公钥解密),此时客户端就可以用公钥进行解密,但是这个中间过程就可以被黑客截胡,黑客拿到之前由服务器向客户端明文发送的公钥来解锁现在用私钥发送的密文。
综上:只使用一对非对称加密,保证了浏览器到服务器的加密安全,但是服务器到浏览器这条路是无法保证安全的。
方案3 —— 双方都使用非对称加密(效率太低不可行)
现在让双方都是以非对称加密。服务端拥有公钥S与对应的私钥S’,客户端拥有公钥C与对应的私钥C’。交易方式如下:
客户端和服务端互相交换公钥
客户端给服务端发消息:先用S对数据加密,再发送,只能由服务器解密,因为只有服务器有私钥S’
服务端给客户端发消息:先用C对数据加密,再发送,只能由客户端解密,因为只有客户端有私钥C’
我们让双方都使用非对称加密,确实保证了双方在互相通信时数据的安全性。但是也有问题:
效率太低(非对称加密的效率要比对称加密慢很多)
同样也使用潜在的安全问题,后续谈
方案4 —— 非对称加密 + 对称加密(仍有安全问题)
既然双方都是以非对称加密的策略导致效率过低,那我们不妨使用非对称加密 + 对称加密的策略,交易方式如下:
仅让服务端具有非对称公钥S和私钥S’
客户端发起https请求,获取服务端公钥S
客户端在本地生成对称密钥C,通过公钥S加密,发送给服务器
由于中间的网络设备没有私钥,即使截获了数据,也无法还原出内部的原文,也就无法获取到对称密钥
服务器通过私钥S’解密,还原出客户端发送的对称密钥C。并且使用这个对称密钥加密给客户端返回的响应数据
后续客户端和服务器的通信都只用对称加密即可。由于该密钥只有客户端和服务器两个主机知道,其他主机 / 设备不知道密钥即使截获数据也没有意义
由于对称加密的效率比非对称加密高很多,因此只是在开始阶段协商密钥的时候使用非对称加密,后续的传输仍然使用对称加密
虽然上面已经比较接近答案了,但是依旧有安全问题(方案2、3、4都有这样的问题):
上面我们的方案都是假设在我们成功完成密钥交换后,中间人才进行的截取,假设中间人早就进行截胡了呢?你怎么保证你客户端获取到的公钥一定就是来自服务端的?中间人不仅是能够获取公钥,也能够篡改公钥。所以上述方案的共性问题:如果最开始,中间⼈就已经开始攻击了呢?
详情见下文。
中间人攻击 —— 针对上面的场景
Man-in-the-MiddleAttack,简称“ MITM攻击 ”
确实,在方案2/3/4中,客户端获取到公钥S之后,对客户端形成的对称秘钥X用服务端给客户端的公钥S进行加密,中间人即使窃取到了数据,此时中间人确实无法解出客户端形成的密钥X,因为只有服务器有私钥S’。
但是中间人的攻击,如果在最开始握手协商的时候就进行了,那就不一定了,假设hacker已经成功成为中间人
中间人操作的过程如下:
服务器具有非对称加密算法的公钥S,私钥S’
中间人具有非对称加密算法的公钥M,私钥M’
客户端向服务器发起请求,服务器明文传送公钥S给客户端
中间人劫持数据报文,提取公钥S并保存好,然后将被劫持报文中的公钥S替换成为自己的公钥M,并将伪造报文发给客户端
客户端收到报文,提取公钥M(自己当然不知道公钥被更换过了),自己形成对称秘钥X,用公钥M加密X,形成报文发送给服务器
中间人劫持后,直接用自己的私钥M’进行解密,得到通信秘钥X,再用曾经保存的服务端公钥S加密后,将报文推送给服务器
服务器拿到报文,用自己的私钥S’解密,得到通信秘钥X
双方开始采用X进行对称加密,进行通信。但是一切都在中间人的掌握中,劫持数据,进行窃听甚至修改,都是可以的
上面的攻击方案,同样适用于方案2、方案3。问题本质出现在:
客户端无法确定收到的含有公钥的数据报文,就是目标服务器发送过来的!也有可能收到的是被恶意篡改窃取数据的黑客发来的。
为了解决这两个问题,就引入了证书。
https协议引入数字证书
服务端在使⽤HTTPS前,需要向CA机构申领⼀份数字证书,数字证书⾥含有证书申请者信息、公钥信息等。客户端向服务器请求公钥时,服务器把证书传输给浏览器,浏览器从证书里获取公钥就行了,证书就如⾝份证,是服务端公钥的身份证明。
这个证书可以理解成是⼀个结构化的字符串, ⾥⾯包含了以下信息:证书发布机构、证书有效期、公钥、证书所有者、签名等。
申请证书的时候,需要在特定平台⽣成CSR,同时⽣成公钥和私钥。这对密钥就是用来在⽹络通信中进行明文加密以及数字签名时使用的。
其中公钥会随着CSR⽂件,⼀起发给CA进⾏权威认证,私钥服务端自己保留,后续用于通信使用(主要就是⽤来交换对称密钥)
当服务端申请CA证书的时候,CA机构会对该服务端进⾏审核,并专门为该⽹站形成数字签名,过程如下:
- CA机构拥有非对称加密的私钥A和公钥A’
- CA机构对服务端申请证书的明⽂数据进⾏hash,形成数据摘要
然后对数据摘要用CA私钥A’加密,得到数字签名S
服务端申请的证书明文和数字签名S 共同组成了数字证书,这样⼀份数字证书就可以颁发给服务端了
注意:每一个浏览器都内置了受信任的证书发布机构的公钥。
7、使用非对称加密+对称加密+数字证书(√)
在客户端和服务器刚⼀建⽴连接的时候, 服务器给客⼾端返回数字证书,证书明文包含了服务端的公钥, 也包含了⽹站的⾝份信息等。
即使证书被中间人窃取,中间人也做不了什么。例如我现在要访问CSDN首页:
1、如果中间人修改证书中的明文信息,由于中间人没有CA机构的私钥,无法生成被修改明文的密文。如果直接转交给客户端,客户端用内置的CA公钥对密文进行解密,同时对明文数据进行哈希,两份哈希值一比对就会发现证书信息被篡改。
2、同样的,如果中间人直接掉包整个CA证书(必须是真的CA证书,假的CA证书无法被浏览器内置公钥解密),客户端一解密,就会发现证书的域名和请求服务器的域名不一致,客户端就会发现服务端给的证书中的信息内容对不上。
客户端拿到证书也就拿到了服务端的公钥,再使用该公钥对对称密钥进行加密,将密文发送给服务端,中间人同样无法对此密文进行解密(因为该密文私钥在服务端手上),服务端拿到密文后使用私钥对密文进行解密,就获得了对称密钥,后续客户端、服务器双方使用对称密钥进行通信即可。因为引入了CA证书,保证了信息的安全性,整个通信过程中间人只能干瞪眼。
被中间人窃取,中间人也做不了什么。例如我现在要访问CSDN首页:
1、如果中间人修改证书中的明文信息,由于中间人没有CA机构的私钥,无法生成被修改明文的密文。如果直接转交给客户端,客户端用内置的CA公钥对密文进行解密,同时对明文数据进行哈希,两份哈希值一比对就会发现证书信息被篡改。
2、同样的,如果中间人直接掉包整个CA证书(必须是真的CA证书,假的CA证书无法被浏览器内置公钥解密),客户端一解密,就会发现证书的域名和请求服务器的域名不一致,客户端就会发现服务端给的证书中的信息内容对不上。
客户端拿到证书也就拿到了服务端的公钥,再使用该公钥对对称密钥进行加密,将密文发送给服务端,中间人同样无法对此密文进行解密(因为该密文私钥在服务端手上),服务端拿到密文后使用私钥对密文进行解密,就获得了对称密钥,后续客户端、服务器双方使用对称密钥进行通信即可。因为引入了CA证书,保证了信息的安全性,整个通信过程中间人只能干瞪眼。
[外链图片转存中…(img-0LxZXk3I-1709176644150)]
还没有评论,来说两句吧...