
文章目錄
- 一.應用層協議--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
協議工作流程:

