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