文章目录
- 一.应用层协议--http协议基础认知
- 二.https协议加密策略解析
- 加密策略1--通信双方只使用对称加密
- 加密策略2--通信双方使用单方非对称加密
- 加密策略3--通信双方都使用非对称加密
- 加密策略4--非对称加密与对称加密配合使用
- 中间人攻击
- 数据签名与CA证书
- HTTPS数据安全认证的本质:非对称加密+对称加密+证书认证
一.应用层协议–http协议基础认知
- 图解
http
协议报文结构:
http
协议默认是无状态协议http-request
中请求行的请求方法最常用的是GET
和POST
GET
和POST
方法都支持用户进行参数提交,GET
方法提交参数通过URL
字段进行提交,POST
方法提交参数通过Cotent
正文进行提交
http
报文解析和封装的实验代码:
#pragma once
#include "log.hpp"
#include "Socket.cpp"
#include <pthread.h>
#include <fstream>
#include <unordered_map>
#include <vector>
#include <iostream>
#include <sstream>
class HttpRequest{const std::string Webroot_ ="./index"; const std::string sep_ = "\r\n";const std::string homepage_ = "index.html";
public:void Deserialize(std::string request){int begin = 0;while(true){std::size_t pos = request.find(sep_,begin);if(pos == std::string::npos){break;}std::string temp = request.substr(begin, pos-begin);if(temp.empty()){begin = pos + sep_.size();break;}req_header_.push_back(std::move(temp));begin = pos + sep_.size();}text_ = request.substr(begin,request.size() - begin);}void Parse(){if(req_header_.size() == 0){lg(Warning,"req_header_ is empty\n");return;}std::stringstream Stream(req_header_[0]);Stream >> method_ >> url_ >> http_version_;file_path_ = Webroot_; if(url_ == "/" || url_ == "/index.html"){file_path_ += "/";file_path_ += homepage_;}else{file_path_ += url_;}auto pos = file_path_.rfind(".");if(pos == std::string::npos){suffix_ = ".html";}else{suffix_ = file_path_.substr(pos);}}void DebugPrint(){for(auto &line : req_header_){std::cout << "--------------------------------" << std::endl;std::cout << line << std::endl;}std::cout << "method: " << method_ << std::endl;std::cout << "url: " << url_ << std::endl;std::cout << "http_version: " << http_version_ << std::endl;std::cout << "file_path: " << file_path_ << std::endl;std::cout << "--------------------------------" << std::endl;std::cout << text_ << std::endl;}
public:std::vector<std::string> req_header_; std::string text_; std::string method_; std::string url_; std::string http_version_; std::string file_path_; std::string suffix_;
};
class http_server{const int size = 4096;class ThreadData{public:ThreadData(int fd, http_server *s) : sockfd(fd), svr(s){}public:int sockfd;http_server *svr;};const std::string Webroot_ ="./index"; const std::string sep_ = "\r\n";const std::string homepage_ = "index.html";
public:http_server(const std::string& de_ip = "172.19.29.44",uint16_t de_port = 8081): socket_(de_ip,de_port){MAP.insert({".html", "text/html"});MAP.insert({".png", "image/png"});}~http_server(){}public:bool Init(){socket_.BuildSocket();socketfd_ = socket_.Get_Server_fd();if(!socket_.SocketBind()){lg(Fatal,"socket bind error\n");return false;}if(!socket_.Socklisten()){lg(Fatal,"socket listen error\n");return false;}return true;}void Start(){while(true){std::string client_ip;uint16_t client_port;int fd = socket_.SockAccept(client_ip,client_port);if(fd < 0){lg(Warning,"Accept error\n");continue;}lg(Info, "get a new connect, sockfd: %d", fd);ThreadData * td = new ThreadData(fd,this);pthread_t tid;pthread_create(&tid,nullptr,Routine,td);}}
private:static void * Routine(void * args){ThreadData * td = static_cast<ThreadData *>(args);pthread_detach(pthread_self());td->svr->HandlerHttp(td->sockfd);delete td;close(td->sockfd);return nullptr;}void HandlerHttp(int sockfd){char buffer[10240];ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);if (n > 0){buffer[n] = 0;std::cout << buffer << std::endl;HttpRequest req;req.Deserialize(buffer);req.Parse();req.DebugPrint();std::string text;bool isFound = true;text = ReadHtmlContent(req.file_path_);if(text.empty()){isFound = false;std::string err_html = Webroot_;err_html += "/";err_html += "err.html";text = ReadHtmlContent(err_html);}std::string response_line;if(isFound)response_line = "HTTP/1.0 200 OK\r\n";elseresponse_line = "HTTP/1.0 404 Not Found\r\n";std::string response_header = "Content-Length: ";response_header += std::to_string(text.size());response_header += "\r\n";response_header += "Content-Type: ";response_header += SuffixToDesc(req.suffix_);response_header += "\r\n";response_header += "Set-Cookie: name=zhounaiqing&&passwd=12345678";response_header += "\r\n";response_header += "Location: https://www.qq.com\r\n";std::string blank_line = "\r\n";std::string response = std::move(response_line);response += std::move(response_header);response += std::move(blank_line);response += std::move(text);send(sockfd, response.c_str(), response.size(), 0);}}std::string SuffixToDesc(const std::string &suffix){auto iter = MAP.find(suffix);if(iter == MAP.end()) return MAP[".html"];else return MAP[suffix];}static std::string ReadHtmlContent(const std::string &htmlpath){std::ifstream in(htmlpath, std::ios::binary);if(!in.is_open()){lg(Warning,"Html_File open error\n");return "";} in.seekg(0, std::ios_base::end);auto len = in.tellg();in.seekg(0, std::ios_base::beg);std::string content;content.resize(len);in.read((char*)content.c_str(), content.size());in.close();return content;}
private:MySocket::Socket socket_;int socketfd_;std::string server_ip_;uint16_t server_port_;std::unordered_map<string,string>MAP;
};
二.https协议加密策略解析
https
协议是基于http
协议的加密通信协议,其很大程度上保证CS
两端的数据安全- 对称加密:同一个密钥可以进行报文的加密和解密操作
- 非对称加密:存在公钥和私钥,私钥加密的报文由公钥进行解密,公钥加密的报文由私钥进行解密,使用上公钥可以对外公开,私钥保密
加密策略1–通信双方只使用对称加密
- 这种加密策略需要双方通信前约定密钥的选择,因此密钥可能外泄,显然是不安全的
加密策略2–通信双方使用单方非对称加密
- 服务器持有公钥和私钥,通信前,服务器将公钥发给客户端完成加密握手协商,后续客户端的请求报文就通过公钥加密发送给服务器
- 该加密策略显然无法保证服务端的报文安全
加密策略3–通信双方都使用非对称加密
- 服务器和客户端都各自持有私钥,通信之前双方先交换公钥完成加密握手协商,后续通过公钥加密报文进行通信,这种通信策略的效率较为低下(非对称加密算法复杂度高)
加密策略4–非对称加密与对称加密配合使用
- 服务端持有私钥
S
,并将公钥S'
发送给客户端,客户端利用公钥S'
,加密自己的对称密钥K
并发送给服务端(保证了密钥K
不外泄)完成加密握手协商,双方后续使用对称密钥K
进行双向通信,这种通信策略的效率较高
- 策略4在四个策略中最优,但是策略2,策略3,策略4在通信前都存在一个加密握手协商的过程,在这个过程中如果存在中间人攻击,进行了密钥置换,就会导致泄密
中间人攻击
- 以策略4为例:
- 上述密钥置换风险的本质是客户端(或服务端)无法识别公钥本身的真正来源,因此必须引入证书补全这个安全漏洞
数据签名与CA证书
CA
证书是由权威机构向服务端机构颁发的公钥身份证,用于确保客户端能够识别出公钥来源的合法性,其识别原理的核心在于证书上的数据签名.CA
证书上的数据签名是一段由CA机构私钥加密的密文,密文中被加密的内容是证书上数据的哈希映射值(并且是不可逆映射),所有的操作系统在出厂前内置了CA机构公开的公钥,因此客户端可以对CA
证书上的数据签名进行解密得到一个原证书数据的哈希散列值Hash1,此时客户端再将证书上的实时数据进行哈希映射得到哈希散列值Hash2,若Hash1
与Hash2
不相同,则说明证书被中间人篡改过,此时客户端可以向用户发出安全性警告.- 需要注意的是,数据签名是由
CA
机构用私钥进行加密的,由于CA
机构的私钥是绝对保密的,因此中间人没有办法重新生成新的数据签名,所以数据签名是绝对权威性的 - CA证书认证过程图解:
HTTPS数据安全认证的本质:非对称加密+对称加密+证书认证
HTTPS
协议工作流程: