Linux网络http与https

应用层协议HTTP

提示
因为现在大多数都是https,所以就用https来介绍http,https比http多了一个加密功能,不影响介绍http。

什么是http

虽然我们说, 应用层协议是我们程序猿自己定的. 但实际上, 已经有大佬们定义了一些现成的, 又非常好用的应用层协议, 供我们直接参考使用. HTTP(超文本传输协议)就是其中之一。
在互联网世界中,HTTP(HyperText Transfer Protocol,超文本传输协议)是一个至关重要的协议。它定义了客户端(如浏览器)与服务器之间如何通信,以交换或传输超文本(如 HTML 文档)。
HTTP 协议是客户端与服务器之间通信的基础。客户端通过 HTTP 协议向服务器发送请求,服务器收到请求后处理并返回响应。HTTP 协议是一个无连接、无状态的协议,即每次请求都需要建立新的连接,且服务器不会保存客户端的状态信息。

域名

在这里插入图片描述

打开浏览器页面,我的默认搜索是百度。
红圈部分是网址,复制粘贴之后,我们无论打开哪个网页,在这个栏目当当中输入https://www.baidu.com/就可以跳转到百度搜索的首页。
这个网址是如何做到这种功能的呢?
网址——>域名——>域名解析——>IP地址

这是因为有域名解析这个功能,将网址转换成ip地址。
Windows打开命令窗口:
在这里插入图片描述
在这里插入图片描述
这里得到一个ip地址,我们输入到浏览器一下:
在这里插入图片描述
也就是说,每个域名都是ip地址,访问每个域名都是通过ip地址。

URL

在百度当中搜索
https://www.helloworld.net/p/4442555963
这一串我们简称为URL,也叫做:统一资源定位符。(网上所有的资源都可以用唯一的一个“字符串”标识获取)
在这里插入图片描述
网络行为
目前我们最常用的网络行为就是把别人的东西拿出来,把自己的东西传上去,我们访问的服务器可以理解为同时连接一台电脑,我们进入这台电脑获取数据或者是上传数据。
url就是搜索目录的存在。

urlencode 和 urldecode

像 / ? : 等这样的字符, 已经被 url 当做特殊意义理解了. 因此这些字符不能随意出现. 比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义。
搜索hello world
https://www.baidu.com/s?tn=15007414_15_dg&ie=utf-8&wd=hello%20world
搜索aaaa+??//: /&bbbb
https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=15007414_15_dg&wd=aaaa%2B%3F%3F%2F%2F%3A%2F%26bbbb&oq=hello%2520world&rsv_pq=eb10b3d000010b64&rsv_t=aa46E6F5%2BL6oqrBlcwAIRYoHHt%2FkY40E5WdjW0FikHG%2B0Wo9hEJLKyWNfAMEq%2BhRJ5K2Pas&rqlang=cn&rsv_dl=tb&rsv_enter=1&rsv_sug3=18&rsv_sug1=15&rsv_sug7=100&rsv_sug2=0&rsv_btype=t&inputT=18981&rsv_sug4=18981

在这里插入图片描述

这里变成了这个样子,说明如果搜索的内容需要这些特殊字符,那么在输入的过程中就会进行转译。
(要求BS双方进行编码和解码)
转义的规则如下:

将需要转码的字符转为 16 进制,然后从右到左,取 4 位(不足 4 位直接处理),每 2 位
做一位,前面加上%,编码成%XY 格式

HTTP 常见 Header

Connection:keep-alive 保持长连接
Content-Type: 数据类型(text/html 等)
Content-Length: Body 的长度
Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
User-Agent: 声明用户的操作系统和浏览器版本信息;
referer: 当前页面是从哪个页面跳转过来的;
Location: 搭配 3xx 状态码使用, 告诉客户端接下来要去哪里访问;
Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;

http请求与响应

http从客户端发到服务器,是怎么发送和接收的呢?
是客户端请求,服务器响应。
请求的结构体:
在这里插入图片描述
这里的\r\n可以看作一种特殊字符,所有的请求内容都是连在一起的,只不过由\r\n隔离起来了而已。
在这里插入图片描述
这是请求的格式。
请求行:
Method是GET/POST,也就是获取与传输。(我们百分之95都是再用这两种命令)
在这里插入图片描述
假设要在网站中输入账号和密码,使用GET,就是通过URL提交的参数。(以问好作为分隔符,右侧是要提交的参数)
注意:参数数量受限,不私秘,会在URL当中体现。
如果用的是POST,那么参数会放在请求正文当中提交。

HTTP Version是http的版本。(1.0,1.1(用的多),2.0)
报头:
里面都是KV属性结构。(里面含有正文长度等等的属性,后面会详细说明)

那么报头的最后一行也是\r\n,怎么才能分辨报头与正文呢?
答案就是,在报头后面加上一个空行。
在这里插入图片描述

同理,请求就要有响应,响应也有自己的结构体:
在这里插入图片描述

Linux输入

telnet www.baidu.com 80
GET / HTTP/1.1
然后按两下回车(因为有空行)
在这里插入图片描述
这里就是报头,报头下面的其他东西就是网页了。
在这里插入图片描述
所以

首先说一下HTTP Version,请求客户端发送给服务器的时候,客户端是什么http版本,服务器就会响应什么http版本。

那么状态码是什么呢?
平时我们访问某个网页,突然蹦出来404,说帖子被删除或者是网页不见了,404就是状态码,后面说的话就是状态码描述符。(字符串版本的描述)

类别原因短语
1XXInformational(信息性状态码)接收的请求正在处理
2XXSuccess(成功状态码)请求正常处理完毕
3XXRedirection(重定向状态码)需要进行附加操作以完成请求
4XXClient Error(客户端错误状态码)服务器无法处理请求
5XXServer Error(服务器错误状态码)服务器处理请求出错

重定向:分为临时和永久。
临时:例如登录页面会跳转到微信或者是QQ,登录完毕之后就会跳转回去。
永久:例如某个域名不用了,公司创建了个新的域名,但是又需要照顾不知道新域名的老用户,所以就会在旧网站提示当前域名不再使用,将要跳转到新网站。(服务器给浏览器发报文,报头当中的Location会指导浏览器应该去访问新的网站)

(现在可以安装一个抓包软件来进行测试了,推荐Fiddler 或者 Postman)
抓包软件是如何工作的呢?
是客户端将http的请求发给Fiddler,Fiddler再发给服务器,相当于Fiddler是一个代理。

简单实现一个httpserver

预备知识

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
第一个参数是读取哪个套接字
第二个参数是读取到哪里
第三个参数是读取的长度
第四个参数是读取的方式

在这里插入图片描述

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
第四个参数是写入方式

在这里插入图片描述
一个巨大的网页会包含非常多的元素,比如打开淘宝京东,琳琅满目的商品,标注的价格,推荐物品,图片,各种其他功能。——每一个元素都是资源,打开首页又很多图片,其实看到的每一张图片都是浏览器发送的访问请求,然后服务器给响应,通过渲染等等手段显示给浏览器。

一次请求响应一个资源,关闭连接——短连接。(http1.0)
客户端通过TCP与服务器建立链接,发送多个请求返回多个响应,在没有完成这些请求和响应之前不会关闭。——长连接(http1.1)

在网页当中插入图片,是需要知道ContentType。(http内容类型)

我们在访问B站的时候,会提示让我们去登录账号密码,登录之后,未来的几天再次进入B站就不用再去登录了,这是为什么呢?
首先明白一点,HTTP协议默认是无状态的,这意味着服务器不会主动记录或保留客户端(如浏览器)的请求历史信息。每个HTTP请求都是独立的,服务器处理完一个请求后,不会“记住”这个客户端的状态,下一次请求时服务器会将其视为全新的请求。
因为http对登录用户有会话保持功能。
原理version:(文件级)
在这里插入图片描述
这里就算是关闭浏览器再打开也可以进去,因为信息被保存在文件里。
在这里插入图片描述
在这里插入图片描述
Cookie是会自动消除的。

内存级如果关闭浏览器,再次打开B站就不会自动登录了。

可如果黑客窃取了cookie文件,就会造成巨大损失。(账号密码被盗,个人隐私泄露)
解决方案:
在这里插入图片描述
也就是说,就算黑客拿到了cookie也是ID,如果在自己的机器登录会被B站检测到,因为B站的session文件中有登录信息,如果IP不同就会让黑客登录账号与密码。(一定程度上避免了信息泄露)

代码实现

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><!-- <form action="/a/b/hello.html" method="post">name: <input type="text" name="name"><br>password: <input type="password" name="passwd"><br><input type="submit" value="提交"></form> --><h1>这个是我们的首页</h1><!-- <img src="/image/1.png" alt="这是一直猫" width="100" height="100"> 根据src向我们的服务器浏览器自动发起二次请求 --><!-- <img src="/image/2.jpg" alt="这是花"> -->
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><h1>这是第二张网页</h1><h1>这是第二张网页</h1><h1>这是第二张网页</h1><h1>这是第二张网页</h1><h1>这是第二张网页</h1><h1>这是第二张网页</h1><h1>这是第二张网页</h1><a href="http://120.78.126.148:8899">回到首页</a><a href="http://120.78.126.148:8899/x/y/world.html">到第三张网页</a>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><h1>这是第3张网页</h1><h1>这是第3张网页</h1><h1>这是第3张网页</h1><h1>这是第3张网页</h1><h1>这是第3张网页</h1><h1>这是第3张网页</h1><a href="http://120.78.126.148:8899">回到首页</a><a href="http://120.78.126.148:8899/a/b/hello.html">到第二张网页</a>
</body>
</html>
#pragma once#include <iostream>
#include <time.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>#define SIZE 1024#define Info 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4#define Screen 1
#define Onefile 2
#define Classfile 3#define LogFile "log.txt"class Log
{
public:Log(){printMethod = Screen;path = "./log/";}void Enable(int method){printMethod = method;}std::string levelToString(int level){switch (level){case Info:return "Info";case Debug:return "Debug";case Warning:return "Warning";case Error:return "Error";case Fatal:return "Fatal";default:return "None";}}void printLog(int level, const std::string &logtxt){switch (printMethod){case Screen:std::cout << logtxt << std::endl;break;case Onefile:printOneFile(LogFile, logtxt);break;case Classfile:printClassFile(level, logtxt);break;default:break;}}void printOneFile(const std::string &logname, const std::string &logtxt){std::string _logname = path + logname;int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666); // "log.txt"if (fd < 0)return;write(fd, logtxt.c_str(), logtxt.size());close(fd);}void printClassFile(int level, const std::string &logtxt){std::string filename = LogFile;filename += ".";filename += levelToString(level); // "log.txt.Debug/Warning/Fatal"printOneFile(filename, logtxt);}~Log(){}void operator()(int level, const char *format, ...){time_t t = time(nullptr);struct tm *ctime = localtime(&t);char leftbuffer[SIZE];snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,ctime->tm_hour, ctime->tm_min, ctime->tm_sec);va_list s;va_start(s, format);char rightbuffer[SIZE];vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);va_end(s);// 格式:默认部分+自定义部分char logtxt[SIZE * 2];snprintf(logtxt, sizeof(logtxt), "%s %s", leftbuffer, rightbuffer);// printf("%s", logtxt); // 暂时打印printLog(level, logtxt);}private:int printMethod;std::string path;
};
Log lg;
#pragma once#include <iostream>
#include <memory>
#include <string>
#include <pthread.h>
#include <fstream>
#include <vector>
#include <sstream>
#include <sys/types.h>
#include <sys/socket.h>
#include <unordered_map>
#include "log.hpp"
#include "Socket.hpp"
using namespace std;
const string wwwroot="./wwwroot"; // web 根目录,在当前文件下的文件夹,里面存放的就是网页里的所有内容
const string sep = "\r\n";
const string homepage = "index.html";
static const int defaultport = 8080;
class HttpServer;
class ThreadData
{
public:ThreadData(int fd, HttpServer *s) : sockfd(fd), svr(s){}ThreadData(){}
public:int sockfd;HttpServer *svr;
};
class HttpRequest
{
public:void Deserialize(string req)//序列化{while(true){size_t pos = req.find(sep);if(pos == string::npos) break;string temp = req.substr(0, pos);if(temp.empty()) break;req_header.push_back(temp);req.erase(0, pos+sep.size());}text = req;}void Parse(){stringstream ss(req_header[0]);ss >> method >> url >> http_version;file_path = wwwroot; // ./wwwrootif(url == "/" || url == "/index.html")//条件满足判断为要访问首页{file_path += "/";file_path += homepage; // ./wwwroot/index.html}else file_path += url;// /a/b/c/d.html->./wwwroot/a/b/c/d.html,无论有多少个参数,都要从wwwroot的web根目录开始查询访问auto pos = file_path.rfind(".");if(pos == string::npos) suffix = ".html";//没找到后缀默认为是.htmlelse suffix = file_path.substr(pos);}void DebugPrint(){for(auto &line : req_header){cout << "--------------------------------" << endl;cout << line << "\n\n";}cout << "method: " << method << endl;cout << "url: " << url << endl;cout << "http_version: " << http_version << endl;cout << "file_path: " << file_path << endl;cout << text << endl;}
public:vector<string> req_header;//请求报头string text;//正文部分// 解析之后的结果string method;string url;string http_version;string file_path; // ./wwwroot/a/b/c.html 2.png文件类型string suffix;//文件后缀
};
class HttpServer
{
public:HttpServer(uint16_t port = defaultport):port_(port){content_type.insert({".html", "text/html"});content_type.insert({".png", "image/png"});}bool Start(){listensock_.Socket();listensock_.Bind(port_);listensock_.Listen();for (;;){string clientip;uint16_t clientport;int sockfd = listensock_.Accept(&clientip, &clientport);if (sockfd < 0)continue;lg(Info, "get a new connect, sockfd: %d", sockfd);pthread_t tid;ThreadData *td = new ThreadData(sockfd, this);pthread_create(&tid, nullptr, ThreadRun, td);}}static string ReadHtmlContent(const string &htmlpath)//http的本质就是读到固定格式的字符串进行分析在分拣中搜索资源,然后在响应回去{ifstream in(htmlpath, ios::binary);//要以二进制的方式去读,因为图片是按照二进制的方式存储的,不然图片会读取失败if(!in.is_open()) return "";in.seekg(0, ios_base::end);auto len = in.tellg();//文件大小in.seekg(0, ios_base::beg);string content;content.resize(len);in.read((char*)content.c_str(), content.size());in.close();return content;}string SuffixToDesc(const std::string &suffix){auto iter = content_type.find(suffix);if(iter == content_type.end()) return content_type[".html"];//没找到返回类型默认是.htmlelse return content_type[suffix];}void HandlerHttp(int sockfd){char buffer[10240];ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);if (n > 0){buffer[n] = 0;cout << buffer << endl; // 假设我们读取到的就是一个完整的,独立的http 请求//响应部分,网页的内容会被拼接到响应正文当中。//特定部分情况下,访问某个服务器URL就不会计算ip地址与端口号,所以剩下的部分就是RUL。//用户请求的时候,会在RUL当中包含请求的页面,什么样的资源,根据路径来寻找相应的资源HttpRequest req;req.Deserialize(buffer);req.Parse();//返回响应过程string text;bool ok = true;text = ReadHtmlContent(req.file_path); if(text.empty())//如果失败就返回404{ok = false;string err_html = wwwroot;err_html += "/";err_html += "err.html";text = ReadHtmlContent(err_html);}string response_line;if(ok)response_line = "HTTP/1.0 200 OK\r\n";elseresponse_line = "HTTP/1.0 404 Not Found\r\n";string response_header = "Content-Length: ";response_header += to_string(text.size()); // Content-Length: 11response_header += "\r\n";response_header += "Content-Type: ";//文件类型response_header += SuffixToDesc(req.suffix);response_header += "\r\n";response_header += "Set-Cookie: name=haha&&passwd=12345";//Cookie文件response_header += "\r\n";string blank_line = "\r\n"; // \nstring response = response_line;response += response_header;response += blank_line;response += text;send(sockfd, response.c_str(), response.size(), 0);}close(sockfd);}static void *ThreadRun(void *args){pthread_detach(pthread_self());ThreadData *td = static_cast<ThreadData *>(args);td->svr->HandlerHttp(td->sockfd);delete td;return nullptr;}~HttpServer(){}
private:Sock listensock_;uint16_t port_;unordered_map<string, string> content_type;//ContentType对照表
};
#include "HttpServer.hpp"int main(int argc, char *argv[])
{if(argc != 2){exit(1);}uint16_t port = std::stoi(argv[1]);std::unique_ptr<HttpServer> svr(new HttpServer(port));svr->Start();return 0;
}

HTTPS

什么是HTTPS

HTTP协议中,用户的信息要么在正文里,要么在URL里,很不安全。
HTTPS也是一个应用层协议. 是在 HTTP 协议的基础上引入了一个加密层. HTTP 协议内容都是按照文本的方式明文传输的. 这就导致在传输过程中出现一些被篡改的情况.
在这里插入图片描述
https = http+ssl
在应用层正文进行加密,然后通过协议栈发送给对方,对方也是在应用层进行解密读取到正文,除了双方的应用层,其他层是看不到这份报文的正文内容的。

加密

加密就是把 明文 (要传输的信息)进行一系列变换, 生成 密文 。
解密就是把 密文 再进行一系列变换, 还原成 明文 。
在这个加密和解密的过程中, 往往需要一个或者多个中间的数据, 辅助进行这个过程, 这样的数据称为 密钥。
例如:
要发送一个数字,7,然后我们可以先进行^5再发给对方,发过去的是2,对方 ^5之后就能拿到7了。
这里7就是明文,2就是密文,5就是密钥。

在以前,去浏览器下载某款应用,如果找不到官网的话,到了别的网站下载这个应用,会发生两种情况,一种是未被劫持,应用下载会成功;如果被劫持应用就会被中间的运营商给替换掉,换成别的应用。
由于我们通过网络传输的任何的数据包都会经过运营商的网络设备(路由器, 交换机等), 那么运营商的网络设备就可以解析出你传输的数据内容, 并进行篡改.
点击 “下载按钮”, 其实就是在给服务器发送了一个 HTTP 请求, 获取到的 HTTP 响应其实就包含了该 APP 的下载链接. 运营商劫持之后,会修改掉这个下载地址。
所以,因为 http 的内容是明文传输的,明文数据会经过路由器、wifi 热点、通信服务运营商、代理服务器等多个物理节点,如果信息在传输过程中被劫持,传输的内容就完全暴露了。劫持者还可以篡改传输的信息且不被双方察觉,这就是 中间人攻击 ,所以我们才需要对信息进行加密。

不止运营商可以劫持, 其他的 黑客 也可以用类似的手段进行劫持, 来窃取用户隐私信息, 或者篡改内容。
在互联网上, 明文传输是比较危险的事情!!!
HTTPS 就是在 HTTP 的基础上进行了加密, 进一步的来保证用户的信息安全。

常见的加密方式

对称加密
采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密,特征:加密和解密所用的密钥是相同的。
就像上面说的传输数字 7 的例子。
特点:算法公开、计算量⼩、加密速度快、加密效率⾼。

非对称加密
需要两个密钥来进行加密和解密,这两个密钥是公开密钥(public key,简称公钥)和私有密钥(private key,简称私钥)。
其中公开密钥可以让所有人都知道,私有密钥只能自己知道,私钥加密的内容可以被公钥进行解密,但是公钥加密的内容只能被私钥解密。
比如说我们发送给一个服务器一条信息(只有这个服务器有私钥),所有人通过公钥进行加密,其他人读取不了这些消息,只有服务器的私钥才能进行解密。
特点:算法强度复杂、安全性依赖于算法与密钥但是由于其算法复杂,而使得加密解密速度没有对称加密解密的速度快。
非对称加密要用到两个密钥, 一个叫做 “公钥”, 一个叫做 “私钥”. 公钥和私钥是配对的. 最大的缺点就是运算速度非常慢,比对称加密要慢很多.

数据摘要 && 数据指纹

数字指纹(数据摘要),其基本原理是利用单向散列函数(Hash 函数)对信息进行运算, 生成一串固定⻓度的数字摘要。数字指纹并不是一种加密机制,但可以用来判断数据有没有被篡改。(将一个字符串通过hash算法转化成一个固定长度,非常低概率冲突的固定长度字符串,被转化的这个字符串具有唯一性——MD5算法)
摘要特征:和加密算法的区别是,摘要严格意义不是加密,因为没有解密,只不过从摘要很难反推原信息,通常用来进行数据对比

上面说的这个例子:
在这里插入图片描述
在第一次输入账号密码认证的时候就会通过MD5算法形成数据摘要(因为每个人的账号是不相同的),然后返回给用户的浏览器,也就是cookit:ID。

百度网盘还有个秒传的功能,这个也是通过MD5的算法来实现的技术。
假设用户A上传了一部电影,电影形成了数据摘要存在了百度网盘的库里,过了一段时间用户B也要上传这部电影,在上传的时候,会将要上传的电影进行数据摘要,然后判断库里是否有这个电影,发现这部电影存在,就会将这个电影变成共享文件,让用户A和用户B通过软连接的方式连接到这个共享文件;如果用户B上传的不是这个电影,那么再进行上传即可。

数字签名
摘要也是可以进行加密的,加密的摘要就叫做数字签名。

HTTPS工作过程探究

逐步设计完善一套安全方案。
假设客户端给服务器发送数据,中间有黑客进行劫持。

方案一:只使用对称加密

在这里插入图片描述
引入对称加密之后, 即使数据被截获, 由于黑客不知道密钥是啥, 因此就无法进行解密, 也就不知道请求的真实内容是啥了,可真的是这样吗?
实则不然,因为密钥也是需要传输给服务器,服务器才知道密钥是什么,那么传输的途中密钥要不要加密呢?加密服务器又不知道了,不加密黑客也会截取到密钥,也能解开密文,所以这种方法不可靠。

方案二:只使用非对称加密

在这里插入图片描述
也就是说,这种方法可以暂时保证客户端传输给服务器的数据不被黑客劫持,但是服务器发送给客户端的数据会被劫持,因为黑客也有公钥,服务器用私钥加密过的密文会被解开。

方案三:双方都使用非对称加密

简单来讲,就是方案二中客户端也生成私钥和公钥,互相传送给对方公钥,双方通过自己的私钥加密,用对方的公钥进行解密。
这样看起来是安全的,但是有和方案二的客户端发送给服务器数据一样的漏洞,并且这种方法效率低下。

方案四:非对称加密+对称加密

在这里插入图片描述
这里本质就是服务器给客户端公钥,客户端通过公钥对自己形成的对称密钥进行加密传给服务器,因为只有服务器才有私钥进行解密,所以看起来就保证了C的安全性,以后的通信同C加密解密即可。
但是,方案二三四的那种漏洞是非常致命的,如果黑客从最开始就从中间进行操作了呢?

方案二三四的致命问题

在这里插入图片描述
如果中间人形成了自己的公钥私钥,将服务器向客户端发送的S替换成M,那么客户端加密C就是用中间人的M进行了加密,并且服务器和客户端都不知道,因为客户端加密之后被中间人拿到,中间人又将C+M进行解密得到C,再让C+S发送给服务器。
这种叫做MITM攻击。
所以说还需要进一步对方案四进行改造才可以解决这个问题。(问题的本质是客户端无法验证服务器发送给自己的公钥是否合法)

引入证书

在边境,有关人员如何确定入境与出境人的身份合法?那就是身份证护照等等“证书”,并且是权威机构颁发的(当地政府)。
同理:服务端在使用 HTTPS 前,需要向 CA 机构申领一份数字证书,数字证书里含有证书申请者信息、公钥信息等。服务器把证书传输给浏览器,浏览器从证书里获取公钥就行了,证书就如身份证,证明服务端公钥的权威性

证书的原理
在这里插入图片描述
1.申请认证证书,首先服务器要有自己的公钥和密钥。准备好:域名/法人/服务器自己的公钥,生成.csr文件发给CA机构去申请证书。
2.CA机构审核是否合法。
3.CA机构审核合法之后进行签发证书,这个证书不是纸笔打印的那种证书,而是安装到服务器上的。
4.服务器发送给客户端证书,不单单是公钥这么简单了。(证书里面有服务器的公钥,这就防止了中间人篡改公钥)
5.客户端验证服务器的证书是否合法。
6.合法之后在进行密钥协商。(发送对称密钥)

CSR文件生成
在这里插入图片描述
服务器对应的公司会将自己的信息生成csr文件,然后生成一个公钥和私钥,这个私钥服务器要自己保存。(这里的公钥是面向客户端的,发送给了CA机构进行认证,私钥就是服务器自己的私钥,也就是说在形成CSR文件前服务器没有公钥和私钥)
签名
在这里插入图片描述

这是CA签名的过程,数据就是证书当中的明文:
在这里插入图片描述
将这个明文进行数据摘要形成一段数据,然后用CA机构自己的私钥进行加密就形成了签名。
然后再次拿出将明文和这个签名合二为一就形成了带有签名的证书。
在这里插入图片描述
注意:签名的形成是基于非对称加密算法。
CA机构也有自己的公钥与私钥。
为什么签名不直接加密,而是要先 hash 形成摘要?
缩⼩签名密文的⻓度,加快数字签名的验证签名的运算速度。

方案五:非对称加密 + 对称加密 + 证书认证

在这里插入图片描述
客户端认证的时候,要拆开签名与明文,进行对比。
当然,每个客户端在出厂的时候都会内置很多权威机构CA的公钥。(和服务器的公钥无关)
在形成签名的时候,CA机构用自己的私钥进行加密,此刻进行认证就需要用CA机构的公钥进行解密形成散列值——数据摘要。
然后让明文也进行数据摘要。
在这里插入图片描述
客户端只认CA的公钥,也就是说,签名只有CA机构才有资格形成签名。(中间人没有CA的私钥,无法修改签名)
这样就不怕黑客修改明文了,就算改了签名,客户端也没有黑客的公钥,无法对签名进行解密,上面的散列值等式就不成立。

可如果黑客将整个证书全都掉包了呢?(黑客自己进行CA认证,发送给客户端)那就搞笑了,浏览器申请访问的是A网站,返回来的证书是B网站的,域名不同,也会被识别出来。

这样就可以防止中间人从一开始进行替换服务器公钥的操作了。

总结HTTPS的保密三组

HTTPS 工作过程中涉及到的密钥有三组.
第一组(非对称加密): 用于校验证书是否被篡改. 服务器持有私钥(私钥在形成 CSR 文件与申请证书时获得), 客户端持有公钥(操作系统包含了可信任的 CA 认证机构有哪些, 同时持有对应的公钥). 服务器在客户端请求时,返回携带签名的证书. 客户端通过这个公钥进行证书验证, 保证证书的合法性,进一步保证证书中携带的服务端公钥权威性。
第⼆组(非对称加密): 用于协商生成对称加密的密钥. 客户端用收到的 CA 证书中的公钥(是可被信任的)给随机生成的对称加密的密钥加密, 传输给服务器, 服务器通过私钥解密获取到对称加密密钥.
第三组(对称加密): 客户端和服务器后续传输的数据都通过这个对称密钥加密解密. 其实一切的关键都是围绕这个对称加密的密钥. 其他的机制都是辅助这个密钥工作的.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/901349.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

讲解贪心算法

贪心算法是一种常用的算法思想&#xff0c;其在解决问题时每一步都做出在当前状态下看起来最优的选择&#xff0c;从而希望最终能够获得全局最优解。C作为一种流行的编程语言&#xff0c;可以很好地应用于贪心算法的实现。下面我们来讲一篇关于C贪心算法的文章。 目录 贪心算法…

vue3中watch的使用示例

使用情况说明&#xff1a; 1、父组件中有个表格&#xff0c;点击表格行的修改基础信息&#xff0c;弹出修改对话框&#xff1b; 2、修改内容点击确认&#xff0c;发送请求&#xff0c;后端更新数据&#xff1b;不修改内容不发送请求&#xff1b; 3、可以连续修改&#xff1b…

Spring MVC 请求类型注解详解

Spring MVC 请求类型注解详解 1. 核心注解分类 Spring MVC 中的请求处理注解分为以下几类&#xff1a; 类别注解示例作用范围方法级注解RequestMapping, GetMapping 等方法级别参数级注解RequestParam, RequestBody方法参数模型/会话注解ModelAttribute, SessionAttributes方…

C#: DxF文件中Spline解析

以下是使用C#解析DXF文件中Spline(样条曲线)的完整代码示例&#xff0c;使用流行的netDxf库来处理DXF文件&#xff1a; 1. 安装netDxf库 首先通过NuGet安装netDxf库&#xff1a; Install-Package netDxf 2. 完整Spline解析代码 using System; using System.Collections.Ge…

【软考系统架构设计师】系统架构设计知识点

1、 从需求分析到软件设计之间的过渡过程称为软件架构。 软件架构为软件系统提供了一个结构、行为和属性的高级抽象&#xff0c;由构件的描述、构件的相互作用&#xff08;连接件&#xff09;、指导构件集成的模式以及这些模式的约束组成。 软件架构不仅指定了系统的组织结构和…

二.springBoot项目集成ElasticSearch及使用

二.springBoot项目集成ElasticSearch及使用 1.依赖引入2.ElasticSearch常见用法 1.依赖引入 <!--elasticsearch搜索引擎--> <!--高版本7.0后TransportClient已被淘汰&#xff0c;用rest-high-level-client代替--> <dependency><groupId>org.elasticse…

微服务多模块构建feign项目过程与一些报错(2025详细版)

目录 1.eureka-server的注意事项 2.eureka-feign的注意事项 3.多模块构建feign项目过程 3.1创建父项目 3.2创建子项目eureka-server 3.3创建子项目eureka-provider 3.4创建子项目eureka-feign 3.5运行 给个点赞谢谢 1.eureka-server的注意事项 eureka-server的yml文件…

第十一届 蓝桥杯 嵌入式 省赛

一、分析 本届的风格又变了一番&#xff0c;但是难度也降低了些。 又是考察了 PWM 和 ADC。 第八、九届也考察了 PWM。建议先复习这两届&#xff0c;再回来模拟。 LCD的显示也提了额外的要求。 1. 功能概述 电位器 R37 输出的模拟电压信号 PA6输出频率固定&#xff0c;占…

小试牛刀-抽奖程序

编写抽奖程序 需求&#xff1a;设计一个抽奖程序&#xff0c;点击抽奖按钮随机抽取一个名字作为中奖者 目标&#xff1a;了解项目结构&#xff0c;简单UI布局&#xff0c;属性方法、事件方法&#xff0c;程序运行及调试 界面原型 ​ 待抽奖&#xff1a; 点击抽奖按钮&#x…

代码随想录算法训练营day2(数组)

华子目录 长度最小的子数组思路 螺旋矩阵思路总结 长度最小的子数组 https://leetcode.cn/problems/minimum-size-subarray-sum/ 思路 使用滑动窗口&#xff0c;left表示滑动窗口的起始点&#xff0c;right表示滑动窗口的终点 class Solution:def minSubArrayLen(self, targ…

6.1 GitHub亿级数据采集实战:双通道架构+三级容灾设计,破解API限制与反爬难题

GitHub 项目数据获取功能设计与实现 关键词:GitHub API 集成、网页爬虫开发、数据存储设计、定时任务调度、异常处理机制 1. 数据获取架构设计 采用双通道数据采集策略,同时使用 GitHub 官方 API 和网页爬虫技术确保数据完整性: #mermaid-svg-XUg7xhHrzFAozG4J {font-fami…

设计模式(结构型)-桥接模式

目录 摘要 定义 类图 角色 具体实现 优缺点 优点 缺点 使用场景 使用案例 JDBC 和桥接模式 总结 摘要 在软件开发领域&#xff0c;随着系统规模和复杂性的不断攀升&#xff0c;如何设计出具有良好扩展性、灵活性以及可维护性的软件架构成为关键挑战。桥接模式作为一…

Go 微服务框架 | 中间件

文章目录 定义中间件前置中间件后置中间件路由级别中间件 定义中间件 中间件的作用是给应用添加一些额外的功能&#xff0c;但是不会影响原有应用的编码方式&#xff0c;想用的时候直接添加&#xff0c;不想用的时候也可以轻松去除&#xff0c;实现所谓的可插拔。中间件的实现…

leetcode 198. House Robber

本题是动态规划问题。 第一步&#xff0c;明确并理解dp数组以及下标的含义 dp[i]表示从第0号房间一直到第i号房间(包含第i号房间)可以偷到的最大金额&#xff0c;具体怎么偷这里不考虑&#xff0c;第i1号及之后的房间也不考虑。换句话说&#xff0c;dp[i]也就是只考虑[0,i]号…

掌趣科技前端面试题及参考答案

你使用 Vue 的频率如何,用得比较多吗? 在前端开发工作中,我对 Vue 的使用较为频繁。Vue 作为一款轻量级、易于上手且功能强大的前端框架,在众多项目里都发挥着重要作用。 在日常的项目里,Vue 的组件化开发特性为我带来了极大的便利。组件化能够将页面拆分成多个小的、可复…

深入解析Python爬虫技术:从基础到实战的功能工具开发指南

一、引言:Python 爬虫技术的核心价值 在数据驱动的时代,网络爬虫作为获取公开数据的重要工具,正发挥着越来越关键的作用。Python 凭借其简洁的语法、丰富的生态工具以及强大的扩展性,成为爬虫开发的首选语言。根据 Stack Overflow 2024 年开发者调查,68% 的专业爬虫开发者…

CSS 笔记——Flexbox(弹性盒布局)

目录 1. Flex 容器与 Flex 项目 2. 主轴与交叉轴 3. Flex 容器的属性 display flex-direction justify-content align-items align-content flex-wrap 4. Flex 项目的属性 flex-grow flex-shrink flex-basis flex align-self 5. Flexbox 的优点 6. Flexbox 的…

Java学习手册:Java反射与注解

Java反射&#xff08;Reflection&#xff09;和注解&#xff08;Annotation&#xff09;是Java语言中两个强大的特性&#xff0c;它们在框架开发和复杂应用中扮演着重要角色。反射允许程序在运行时检查和操作类、对象、接口、字段和方法&#xff0c;而注解则提供了一种元数据形…

JavaWeb遇到的问题汇总

问题一&#xff1a;&#xff08;键值对最后一项没有逗号&#xff09; 在JSON字符串转自定义对象和自定义对象转JSON字符串时&#xff1a; 如图所示&#xff1a;若忘记删除键值对的最后一项没有逗号时&#xff0c;则下一句转换不会生效&#xff0c;应该删除最后一项的逗号。 解…

模板引擎语法-变量

模板引擎语法-变量 文章目录 模板引擎语法-变量&#xff08;一&#xff09;在Django框架模板中使用变量的代码实例&#xff08;二&#xff09;在Django框架模板中使用变量对象属性的代码实例&#xff08;三&#xff09;在Django框架模板中使用变量显示列表 &#xff08;一&…