应用层http协议包解析与https加密策略解析

news2024/9/22 1:36:44

在这里插入图片描述

文章目录

  • 一.应用层协议--http协议基础认知
  • 二.https协议加密策略解析
    • 加密策略1--通信双方只使用对称加密
    • 加密策略2--通信双方使用单方非对称加密
    • 加密策略3--通信双方都使用非对称加密
    • 加密策略4--非对称加密与对称加密配合使用
    • 中间人攻击
    • 数据签名与CA证书
    • HTTPS数据安全认证的本质:非对称加密+对称加密+证书认证

一.应用层协议–http协议基础认知

  • 图解http协议报文结构:
    在这里插入图片描述
  • http协议默认是无状态协议
  • http-request中请求行的请求方法最常用的是GETPOST
    • GETPOST方法都支持用户进行参数提交,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>
//协议请求处理类-->request反序列化处理类
class HttpRequest{
    const std::string Webroot_ ="./index"; // web 根目录
    const std::string sep_ = "\r\n";
    const std::string homepage_ = "index.html";
public:
    //反序列化接口-->获取请求报头和正文字段-->报头存在vector中,text放在string中
    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);
    }
    //解析http报头第一行的内容,包括请求方法,请求的资源路径,请求的资源url,http协议版本,请求中的服务器资源路径
    //获取的url是服务器端口号之后的资源路径信息
    void Parse(){
        if(req_header_.size() == 0){
            lg(Warning,"req_header_ is empty\n");
            return;
        }
        //将协议报头的第一行以空格为分隔符,分别存入三个string中
        std::stringstream Stream(req_header_[0]);
        Stream >> method_ >> url_ >> http_version_;
        //从报头第一行的url字段中提取出资源在服务器上的路径和所请求的资源的文件后缀
        file_path_ = Webroot_;  //前缀加上服务器根目录
        if(url_ == "/" || url_ == "/index.html"){
            //构建Web主页路径
            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_;                      //协议正文字段

    //http报头解析结果
    std::string method_;         //请求中的方法
    std::string url_;            //请求中的url字段
    std::string http_version_;   //请求中的http协议版本
    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"; // web 根目录
    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;
    }


    //处理http请求并构建http回应
    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();

            //构建http响应
            //读取客户端请求的文件资源,构建http响应正文
            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);
                //读取404页面返回给客户端
            }

            //构建http响应报头第一行
            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";
            
            //构建http响应报头中的各个属性字段
            //正文长度
            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";
            //设置浏览器缓存-->浏览器的下一次请求中url会加上该字段
            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";

            //构建完整http回应字段
            std::string response = std::move(response_line);
            response += std::move(response_header);
            response += std::move(blank_line);
            response += std::move(text);
            //向客户端发送http回应
            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,若Hash1Hash2不相同,则说明证书被中间人篡改过,此时客户端可以向用户发出安全性警告.
  • 需要注意的是,数据签名是由CA机构用私钥进行加密的,由于CA机构的私钥是绝对保密的,因此中间人没有办法重新生成新的数据签名,所以数据签名是绝对权威性的
  • CA证书认证过程图解:
    在这里插入图片描述

HTTPS数据安全认证的本质:非对称加密+对称加密+证书认证

  • HTTPS协议工作流程:
    在这里插入图片描述
    在这里插入图片描述

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

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

相关文章

Java基于SpringBoot网上超市的设计与实现论文

摘 要 网络技术和计算机技术发展至今&#xff0c;已经拥有了深厚的理论基础&#xff0c;并在现实中进行了充分运用&#xff0c;尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代&#xff0c;所以对于信息的宣传和管理就很关键。因此超市商品销售信…

外贸业务员没客户的7大原因+解决办法!

业务员没有客户&#xff0c;就是无源之水&#xff0c;无本之木&#xff0c;这自然也就没有业绩。那些吃空饷的业务员&#xff0c;迟早会拖垮公司。所以不管是什么原因导致的业务员没客户&#xff0c;都要一一查验清楚。七个业务员没有客户的原因&#xff0c;七种对策&#xff0…

小朋友来自多少小区 - 华为OD统一考试(C卷)

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 幼儿园组织活动&#xff0c;老师布置了一个任务&#xff1a; 每个小朋友去了解与自己同一个小区的小朋友还有几个。 我们将这些数量汇总到数组 garden 中。 请…

IEEE754标准的c语言阐述,以及几个浮点数常量

很多年前&#xff0c;调研过浮点数与整数之间的双射问题&#xff1a; win7 intel x64 cpu vs2013 c语言浮点数精度失真问题 最近重新学习了一下IEEE754标准&#xff0c;也许实际还有很多深刻问题没有被揭示。 计算机程序设计艺术&#xff0c;据说这本书中也有讨论。 参考&…

uni-app去除页面头部的标题栏

uniapp项目 每个界面都会有一个标题栏 配置在我们项目根目录的 pages.json中 我们将它全部去掉 上面还是有一条黑的 体验非常差 我们只需要在pages.json中 指定page的 style中加入 "navigationStyle": "custom"对应的page 就没有这个标题栏了

Spring 源码解析

文章目录 前言相关Spring的定义接口整体代码StartupStep contextRefresh this.applicationStartup.start("spring.context.refresh")prepareRefresh()obtainFreshBeanFactory()registerBeanPostProcessors(beanFactory)SpringAOP原码流程EnableAspectJAutoProxyAnno…

协方差矩阵计算

文章目录 协方差矩阵计算原理python实现 协方差矩阵 协方差矩阵反映了两个随机变量变化时是同向还是反向的&#xff08;相关性&#xff09;。 如果协方差>0&#xff0c;则说明这两个随机变量同向变化。 协方差矩阵<0&#xff0c;则说明是反向变化。 协方差矩阵0&#xf…

【MySQL】查询语句:条件、排序和分页

基本查询 MySQL 数据库使用SELECT语句来查询数据。 查询字段 以下为在MySQL数据库中查询数据通用的 SELECT 语法&#xff1a; SELECT 字段名,字段名... FROM 表名;选择全部列 SELECT * FROM emp; -- 查询所有字段一般情况下&#xff0c;除非需要使用表中所有的字段数据&…

React入门之React_使用es5和es6语法渲染和添加class

React入门 //react的核心库 <script src"https://cdn.jsdelivr.net/npm/react17/umd/react.development.js"></script> //react操作dom的核心库&#xff0c;类似于jquery <script src"https://cdn.jsdelivr.net/npm/react-dom17/umd/react-dom.…

【知识分享】配电网重构知识及matlab实现

目录 一、理论分析 二、程序介绍 1.基本环矩阵M的matlab代码 2.智能算法重构代码 三、下载链接 配网重构中&#xff0c;很重要的一个约束条件为配网应随时保持开环、辐射的状态&#xff1a; 配电网系统是属于闭环设计但是开环运行的系统&#xff0c;因此&#xff0c;在开关…

考取ORACLE数据库OCP的必要性 Oracle数据库

OCP证书是什么&#xff1f; OCP&#xff0c;全称Oracle Certified Professional&#xff0c;是Oracle公司的Oracle数据库DBA&#xff08;Database Administrator&#xff0c;数据库管理员)认证课程。这是Oracle公司针对数据库管理领域设立的一项认证课程&#xff0c;旨在评估和…

Java ZooKeeper-RocketMQ 面试题

Java ZooKeeper-RocketMQ 面试题 前言1、谈谈你对ZooKeeper的理解 &#xff1f;2、Zookeeper的工作原理&#xff08;Zab协议&#xff09;3、谈谈你对分布式锁的理解&#xff0c;以及分布式锁的实现&#xff1f;4、 zookeeper 是如何保证事务的顺序一致性的&#xff1f;5、 zook…

Unity 向量计算、欧拉角与四元数转换、输出文本、告警、错误、修改时间、定时器、路径、

using System.Collections; using System.Collections.Generic; using UnityEngine;public class c2 : MonoBehaviour {// 定时器float t1 0;void Start(){// 向量Vector3 v1 new Vector3(0, 0, 2);Vector3 v2 new Vector3(0, 0, 3);// 计算两个向量的夹角Debug.Log(Vector3…

Netty的InboundHandler 和OutboundHandler

一、InboundHandler 和OutboundHandler的区别 在Netty中&#xff0c;"inbound"表示来自外部来源&#xff08;如网络连接&#xff09;的数据&#xff0c;而"outbound"则表示从应用程序发送到外部目标&#xff08;如网络连接或其他服务&#xff09;的数据。…

如何使用 CrewAI 构建协作型 AI Agents

一、前言 AI Agents 的开发是当前软件创新领域的热点。随着大语言模型 (LLM) 的不断进步&#xff0c;预计 AI 智能体与现有软件系统的融合将出现爆发式增长。借助 AI 智能体&#xff0c;我们可以通过一些简单的语音或手势命令&#xff0c;就能完成以往需要手动操作应用程序才能…

QT绘图

QPainter paintEvent是Qt中一个非常重要的函数&#xff0c;它是QWidget类的一个事件处理函数&#xff0c;用于处理小部件的绘制事件。当Qt认为小部件需要重绘时&#xff08;例如&#xff0c;窗口首次出现时&#xff0c;大小改变时&#xff0c;或者调用了小部件的update()方法时…

JVM(5)

垃圾回收相关 垃圾收集器 警告:纯八股文! 如果说上面我们讲的收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体体现. 垃圾收集器的作用:垃圾收集器是为了保证程序能够正常,持久运行的一种技术,它是将程序中不用的死亡对象也就是垃圾对象进行清除,从而保证新的…

【 C++ 】空间配置器

1、什么是空间配置器 空间配置器&#xff0c;顾名思义就是为各个容器高效的管理空间(空间的申请与回收)的&#xff0c;在默默地工作。虽然在常规使用STL时&#xff0c;可能用不到它&#xff0c;但站在学习研究的角度&#xff0c;学习它的实现原理对我们有很大的帮助。 2、为什…

P4715 【深基16.例1】淘汰赛题解

题目 有&#xff08;n≤7&#xff09;个国家参加世界杯决赛圈且进入淘汰赛环节。已经知道各个国家的能力值&#xff0c;且都不相等。能力值高的国家和能力值低的国家踢比赛时高者获胜。1号国家和2号国家踢一场比赛&#xff0c;胜者晋级。3号国家和4号国家也踢一场&#xff0c;…

zephyr学习

zephyr内核对象学习 定时器 类似linux的定时器&#xff0c; 可以分别设置第一次到期时间和后续的周期触发时间&#xff0c; 可以注册到期回调和停止回调 还有一个计数状态&#xff0c;用于标记timer到期了多少次 duration&#xff1a;设定timer第一次到期的时间。 period: …