Linux的应用层协议——http和https

发布于:2025-07-31 ⋅ 阅读:(22) ⋅ 点赞:(0)

http

简要概念

域名

在这里插入图片描述
域名,也就是服务器地址,会被解析成IP地址,从下图我们可以看到访问百度的网站和访问百度的IP的效果是一样的
在这里插入图片描述
我们在访问这个网页的时候并没有添加端口号,http绑定的端口一般都是80,https绑定的端口一般都是443,在我们搜索后会自动帮我们添加默认端口号,而不需要我们手动去添加端口号

URL

URL(Union Resource Located)统一资源定位符,所有网络上的资源,可以通过唯一的字符串标识和获取
在这里插入图片描述

1.协议(Protocol):指定访问资源所使用的协议类型,例如HTTP、HTTPS、FTP等。协议决定了客户端和服务器之间通信的方式,http绑定的端口一般都是80,https绑定的端口一般都是443
2.服务器地址(Hostname):提供服务的服务器的名称,可以是域名或IP地址。例如:www.baidu.com或183.232.231.173。
3.端口号(Port):指定服务器上的特定服务,默认为80(HTTP)或443(HTTPS)。端口号的范围从0到65535。
4.路径(Path):资源在服务器上的位置,以斜杠(/)开头。例如:/img/bdlogo.gif,第一个/一般代表web的根目录,但也可以选择一些合适的相对路径作为根目录
5.查询参数(Query Parameters):对资源进行进一步描述或限制的参数,以问号(?)开头,多个参数之间用&分隔。例如:?name=bob&id=123。
6.片段(Fragment):文档内部某个位置的标识符,以井号(#)开头。例如:#main。

这里会有一个问题,一个URL里包含类似于:/?等特殊字符才能进行搜索,那么如果我刚好需要搜索这些特殊字符的话,web会如何处理。
在这里插入图片描述
可以看到aaaaa和bbbbb中间的字段被编码,当数据本身包含和URL中冲突的特殊字符,就需要要求BS双方进行编码和解码,转义的规则:将需要转码的字符转化为16进制,接着从右往左取四位(不足四位按四位处理),每两位当做一位,前面加上%,编码成%XY的格式

http协议格式

http请求

在这里插入图片描述

#pragma once
#include <string>
using namespace std;
#include "TCP.hpp"
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <cstring>
#include "log.hpp"

class httpserver;

class httpdate
{
public:
public:
    int socket;
    httpserver *s;
};

class httpserver
{
public:
    httpserver(string ip, uint16_t port)
        : _ip(ip), _port(port)
    {
        _listensocket.CreateSocket();
        _listensocket.BindSocket(_port, _ip);
        _listensocket.ListenSocket(5);
    }

    void run()
    {
        while (1)
        {
            string clientip;
            uint16_t clientport;
            int socket = _listensocket.AcceptSocket(&clientip, &clientport);
            if (socket < 0)
            {
                log(Warning, "accept fail,errno is %d,error is %s\n", errno, strerror(errno));
                continue;
            }
            log(Info, "accept success,socketfd is %d\n",socket);
            // 连接成功
            pthread_t tid;
            httpdate* clientdata=new httpdate;
            clientdata->socket = socket;
            pthread_create(&tid, nullptr, server, clientdata);
        }
    }

    static void Hander(httpdate *arg)
    {
        char buffer[10240];
        ssize_t ret = recv(arg->socket, buffer, sizeof(buffer), 0);
        if (ret > 0)
        {
            buffer[ret] = '\0';
            cout << buffer << endl;

            // 构建一个简单的HTTP响应
            const char *response =
                "HTTP/1.1 200 OK\r\n"
                "Content-Type: text/html\r\n"
                "\r\n"
                "<html><body><h1>Hello, World!</h1></body></html>";

            send(arg->socket, response, strlen(response), 0);
        }
        close(arg->socket);
    }

    static void *server(void *args)
    {
        pthread_detach(pthread_self());
        httpdate *arg = static_cast<httpdate *>(args);
        arg->s->Hander(arg);
        return nullptr;
    }

public:
    string _ip;
    uint16_t _port;
    TCP _listensocket;
};

在这里插入图片描述
User-Agent代表访问的设备的基本信息

http响应

200表示网页正常,404之类的状态码表示找不到网页等问题
在这里插入图片描述
在这里插入图片描述

http内容

http方法

GET 用于从服务器获取资源。通常用于请求数据而不对数据进行修改,例如获取网页或图片。数据都是通过表单提交的,比如说我们在登录的时候,GET会把登录的用户名和密码都加到URL里,并且是明文传输,所以这并不安全
POST 向服务器发送数据以创建新资源。常用于提交表单或上传文件,数据包含在请求体中。和GET不同的是,POST会把用户名和密码加入到正文里,相同的是这一部分数据都是明文传输的
PUT 用于更新服务器上的资源。如果资源不存在,则创建新资源。PUT 通常是幂等的,即多次执行相同请求不会产生不同结果。
DELETE 用于删除服务器上的指定资源。
PATCH 对资源进行部分修改,而不是替换整个资源。
HEAD 类似于 GET,但只返回响应头部信息,不返回实际数据。常用于检查资源是否存在或获取元数据。
OPTIONS 用于查询服务器支持的请求方法,通常用于跨域资源共享(CORS)的预检请求。
TRACE 回显服务器收到的请求,主要用于诊断和调试。
CONNECT 建立到服务器的隧道,通常用于 HTTPS 连接。

状态码

在这里插入图片描述
重定向包括临时重定向和永久重定向,临时重定向表示资源暂时被移动到了一个新的URL,服务器返回的location字段里给浏览器发送回了目标地址,但仍有可能返回原始URL。搜索引擎会继续抓取和索引原始URL,因为它们认为这是临时的变动。而永久重定向表示资源已经永久地移动到了一个新的URL。与临时重定向不同,搜索引擎会更新它们的索引,将原始URL替换为新的URL
在这里插入图片描述

报头属性

请求报头和响应报头里很多属性是可以公用的
在这里插入图片描述
短连接表示请求一次后就断开连接,短连接表示在完成一轮请求的时候连接不会断开,所以这里有一个字段称为Connection,如果是长连接会显示keep-alive

Set-Cookie

http协议默认是无状态的,在我们访问第一个网页之后是有缓存的,但第二次访问的时候还是会向服务端请求,但我们现在访问的网页基本上都会记录我们的登录状态,浏览器是一个进程,如果是文件级的cookie文件,是存在磁盘的,关闭浏览器,第二次访问浏览器的时候依旧可以访问cookie文件,如果是内存级,浏览器关闭后就无法再次访问这个cookie文件
在这里插入图片描述
我这边使用的是类似于上图的png作为图片,在添加cookie字段后,我们会发现浏览器自动给我们保存了此cookie,这样就实现了一个会话保持的功能

static void Hander(httpdate *arg)
    {
        char buffer[20480];
        ssize_t ret = recv(arg->socket, buffer, sizeof(buffer), 0);
        if (ret > 0)
        {
            buffer[ret] = '\0';
            HttpRequest* request=new HttpRequest;
            string out=buffer;
            request->Deserialization(out);
            //cout<<"out#"<<out<<endl;
            //request->HttpDebug();
            //cout << buffer << endl;
            string text=ReadHtmlContent(request->URL);
            //不需要再重新编译,修改html文件的时候,服务器可以一直运行,但客户端重新访问的时候可以看到修改的内容
            //添加报头
            string responseline="HTTP/1.1 200 OK\r\n";
            string responseheader="Content-Length: ";//文件的大小
            responseheader+=to_string(text.size());
            responseheader+="\r\n";
            //文件的属性,否则浏览器就无法识别

            responseheader+="Content-Type: ";
            responseheader+=request->SuffixToDesc();
            responseheader+="\r\n";
            // cout<<"Content-Type:"<<request->SuffixToDesc()<<endl;

            responseheader+="Set-Cookie: name=vientiane&&passwd=123456\r\n";

            
            string responseblank="\r\n";
            string response=responseline;
            response+=responseheader;
            response+=responseblank;
            response+=text;
            // // 构建一个简单的HTTP响应
            cout<<"response#"<<response<<endl;

            send(arg->socket, response.c_str(), response.size(), 0);
        }
        close(arg->socket);
    }

    static void *server(void *args)
    {
        pthread_detach(pthread_self());
        httpdate *arg = static_cast<httpdate *>(args);
        arg->s->Hander(arg);
        return nullptr;
    }

在这里插入图片描述
在这里插入图片描述
可以看到这里面的cookie文件有保存需要的数据,但这里有一个问题,客户端的防范能力几乎为0,cookie文件容易被盗取,所以就出现session+cookie的解决方案

session

在客户端登录的时候,把请求报文发给服务器认证的时候,服务器会在自己底层生成一个session文件,用于保存用户登录相关的内容,每一个session文件都会有一个sessionID,sessionID不会冲突,所以服务端会返回一个响应报文,调用用户的Set-Cookie,把用户的sessionID保存在Cookie里,session文件是由特定的数据结构管理起来的,这样cookie依旧可以被盗取,但用户信息就不会被泄漏了
在这里插入图片描述
但我们可以看到cookie信息被盗取的问题依旧是没有解决的,但sessionID是被服务器分配的,当服务端甄别到登录有异常就会回收sessionID,这样即使盗取对应信息也没有办法访问

https

https也是一个应用层协议,只是在http上添加了一个加密层,加密就是把明文通过一系列变换,变为密文,解密就是把密文通过一系列变换,转化为明文,中间辅助变为密文的字段称为密钥
在这里插入图片描述

由于加密了,所以下面的网络层,数据链路层和传输层都不知道密文的内容,只有传输双方的应用层才知道数据是什么,http层加上一层加密解密层就是https协议
如果没有加密,http是明文传输的,中间会经过WiFi网点,运营商,路由器等,那么就可能会收到中间人攻击,比如说我们在下载一个软件的时候,点击下载,就给服务器发送了一个HTTP请求,但无论是什么请求都会经过运营商,运营商挟持之后,就把响应给修改了,把返回的地址改为qq浏览器等其他软件的下载地址

加密方式

对称加密

采用单钥密码系统的加密方法,同一个密钥可以用于数据的加密和解密,这种方法称为对称加密或者单密钥加密,像DES,3DES等。
假设明文A为1234,密钥key为5,可以按位与的把数据加密,然后发送到另外一个端口后,对方再按位与一次把数据解密,得到原来的明文,这种加密运行速度快,计算量小

非对称加密

需要两个密钥进行加密和解密,这两个密钥是公开密钥,和私有密钥,通过公钥把明文加密,变为密文,再通过私钥对密文解密,变为明文,也就是说如果我们使用私钥加密,拥有公钥的人都可以进行解密,如果我们使用公钥进行加密,那么只有拥有私钥的人可以进行解密,这一过程也可以反着用,像DSA等算法,但这种加密的运行速度非常慢,计算量大

数据摘要/数据指纹

这项技术的基本原理是使用单向哈希对数据进行运算,生成一串固定长度的数据摘要,这并不是一项加密技术,而是一项判断数据有没有被篡改的技术,有MD5,SHA1等算法,从数据摘要是很难反推原信息的,一般都用于进行数据对比,其实服务端的sessionID就可以依靠这种技术进行处理,只要有一点点的不同,生成的数据摘要就是天差地别的,也可以用于上传云端的功能,如果我们现在需要上传一份资源,而在此之前已经有人上传了,生成了对应的数据指纹,上传云端就不需要再次下载,而是在服务器上生成一个软链接文件,然后指向已经上传在云端的资源

数字签名

数据摘要经过私钥加密后变成数字签名,用于验证原始文章是否被修改。
CA机构有自己的公钥和私钥,用户提交上来的数据通过公开的散列函数进行运算得到一组散列值,然后再通过CA机构的私钥进行加密,才形成签名,散列其实是为了不让中间人用公钥直接访问到明文,而且哈希后也可以提高运算效率
所以客户端收到了服务器发来的证书后,可以通过公钥验证证书
在这里插入图片描述

证书

CA认证

服务端在使用https的时候,需要向CA机构认领一份数字证书,证书里有证书申请者信息,公钥信息等,然后服务器把证书传给浏览器,浏览器再从证书里提取签名和明文,通过哈希算法把明文映射为数据摘要,对签名用CA公钥解密获得另一个数据摘要,再对两个数据摘要进行对比就可以判断数据有没有被篡改
在这里插入图片描述
在这里插入图片描述

设计方案

方案1:如果只使用对称加密,那么密钥只能由一端产生,但如何安全的传到另一端是一个问题。
方案2:如果只使用非对称加密,服务器可以把公钥发送给客户端,只保留私钥,客户端那边加密的数据发送回服务端才能解密,中间商无法修改数据,但有一个问题,如果服务器想把数据发送回客户端,就只能用私钥加密,而客户和黑客是都可以获取公钥的,就都可以对响应数据进行解密。
方案3:如果客户端和服务端都使用非对称加密,但这样效率太低
方案4:如果使用非对称加密和对称加密混合使用,也就是说服务端采用非对称加密,客户端先请求服务器获得公钥,然后再在本地生成对称密钥,用公钥加密发送给服务端,接下来都获得密钥后,只使用对称密钥通信即可。

方案3和4看起来很安全,但这是建立在中间人只在后续通信过程中参与数据交互的情况下的。方案2,3,4最开始都是通过非对称加密把数据发送出去的,如果中间人在客户请求的时候就开始参与了,那么客户端请求的时候,中间人就把客户端的请求发给服务端,在服务端响应的时候,中间人可以把发往客户端的公钥保存下来,然后把自己生成的公钥发送给客户端,服务端在接下来发送数据的时候,就会使用中间人生成的公钥对数据进行加密,发送过程中依旧会经过中间人,中间人就可以对密文数据解密,再用服务器端的公钥进行加密,服务器就无法发现这一串数据有没有被篡改过,这就是中间人攻击(MITM攻击),这里的本质问题是客户端无法发现接收到的公钥是无效的,这就涉及到证书

方案5:使用对称加密,非对称加密和证书三者结合,在验证证书合法性的时候,客户端使用和CA一样的公开哈希算法把证书生成数据摘要,再用CA公钥把证书的数字签名解密了,对比两份数据是否一样,若不一样,则数据被修改过,若一样,则这一份证书可信,如果中间人想修改签名,也做不到,因为中间人没有CA的私钥,如果想修改明文,那么解密签名和明文加密后的信息就匹配不上,即使中间人申请了一个合法的CA证书,域名也匹配不上
在这里插入图片描述

总结

综上,https工作过程中涉及的密钥有三组,第一组是非对称加密,服务器持有私钥(在生成csr文件获得的),客户端持有公钥(客户端包含可信任的机构的公钥),用于保证服务器返回的证书的合法性。第二组也是非对称加密,客户端用收到CA证书的密钥给随机生成的密钥加密,服务器通过私钥来解密,获得对应的密钥。第三组是对称加密,服务器和客户端可以通过第二组获得的密钥来通信


网站公告

今日签到

点亮在社区的每一天
去签到