文章目录 一.应用层协议--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" ; else response_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
协议工作流程: