目录
- 应用层协议
- 序列化与反序列化
- JSON
- 网络版本计算器
- URL
- urlencode和urldecode
- HTTP协议
- 简单认识HTTP协议
- HTTP协议格式
- HTTP的一些方法
- HTTP状态码
- Http的特征
- cookie
- Connection
- HTTPS
- HTTPS是什么
- 加密与解密
- 常见的加密方式
- 对称加密
- 非对称加密
- 什么是数据摘要
- 什么是证书
- HTTPS如何安全握手
应用层协议
序列化与反序列化
序列化:结构化数据转换为字节流数据。
反序列化:字节流转换为结构化数据。
作用:
- 降低编写应用层代码难度,解决通信成本难题。
- 结构化数据一般给上层业务使用。
- 网络比较适合传输字节流式数据。
协议定制:
- 定义请求与响应的字段需要哪些,字段本身就是协议的一部分
JSON
JSON(JavaScript对象表示法)是一种轻量级的数据交换格式,易于人们阅读和编写,也易于机器解析和生成。
它是一种完全与语言无关的文本格式,但使用了C系列语言程序员熟悉的约定,包括C、C++、C#、Java、JavaScript、Perl、Python等等。
JSON通常用于在服务器和Web应用程序之间传输数据,作为XML的替代方案。它也常用于配置文件和数据存储。JSON数据表示为键值对,其中键是字符串,值可以是字符串、数字、布尔值、数组或其他JSON对象。
网络版本计算器
将客户端发送的结构化数据序列化为字节流式,将字节流式数据从网络传输到服务器,再在服务器端进行反序列化,将字节流式数据反序列化为结构化数据进行计算,再将计算结果序列化为字节流式数据再传输到网络中,由客户端接收。
这种,能够保证一端发送时构造的数据,在另一端能够正确进行解析的约定,就是应用层协议。
URL
平时我们俗称的 “网址” ,其实就是说的 URL。
协议名称://server ip[:80]/a/b/c/d/e.html
->定义互联网中唯一的资源:URL,统一资源定位符
server ip -> 确定唯一的机器
[:80] -> 该服务器提供服务的进程
/a/b/c/d/ -> 客户要访问的资源路径
绝对路径?并非,该资源路径是基于当前web根路径的相对路径
e.html -> 客户要的文件名
全球范围内所有资源,只要找到它的url就能访问该资源。基于这种方式来获取资源称为WWW(World Wide Web),万维网。
urlencode和urldecode
像 / ? :
等这样的字符,已经被url当做特殊意义理解了,因此这些字符不能随意出现。
比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义,转义的规则:将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式。
urldecode是urlencode的逆过程。
HTTP协议
基于请求和响应的这种模式,称之为CS模式。交互的就是双方的报文。
http协议是应用层的协议,底层采用的叫做tcp。http之前已经完成三次握手的动作。
简单认识HTTP协议
- 单纯在报文角度,http可以是基于行的文本协议。
http通过空行的方式区分报头和有效载荷。
- 一个简单的http demo
#include <iostream>
#include <memory>
#include <cassert>
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "Util.hpp"
#include "HttpServer.hpp"
#include "Usage.hpp"
// 一般http都要有自己的web根目录
#define ROOT "./wwwroot"
// 如果客户端只请求了一个/, 返回默认首页
#define HOMEPAGE "index.html"
void HandlerHttpRequest(int sockfd)
{
// 1. 读取请求 for test
char buffer[10240];
ssize_t s = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
if (s > 0)
{
buffer[s] = 0;
}
std::cout << buffer << "\n--------------------\n"
<< std::endl;
std::vector<std::string> vline;
Util::cutString(buffer, "\n", &vline);
std::vector<std::string> vblock;
Util::cutString(vline[0], " ", &vblock);
std::string file = vblock[1];
std::string target = ROOT;
if (file == "/")
file = "/index.html";
target += file;
std::cout << target << std::endl;
std::string content;
std::ifstream in(target);
if (!in.is_open())
{
}
else
{
std::string line;
while (std::getline(in, line))
{
content += line;
}
in.close();
}
std::string HttpResponse;
if (content.empty())
{
HttpResponse = "HTTP/1.1 301 Moved Permanently\r\n";
HttpResponse += "Location: http://8.130.119.166:8081/a/b/404.html\r\n";
}
else
{
HttpResponse = "HTTP/1.1 200 OK\r\n";
HttpResponse += ("Content-Type: text/html\r\n");
HttpResponse += ("Content-Length: " + std::to_string(content.size()) + "\r\n");
HttpResponse += "Set-Cookie: 这是一个cookie\r\n";
}
HttpResponse += "\r\n";
HttpResponse += content;
// std::cout << "########start#################" << std::endl;
// for(auto &iter : vblock){
// std::cout << "---" << iter << "\n" << std::endl;
// }
// std::cout << "##########end###############" << std::endl;
// 2. 试着构建一个http的响应
send(sockfd, HttpResponse.c_str(), HttpResponse.size(), 0);
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
Usage(argv[0]);
exit(0);
}
std::unique_ptr<HttpServer> httpserver(new HttpServer(atoi(argv[1]), HandlerHttpRequest));
httpserver->Start();
return 0;
}
HTTP协议格式
请求:
首行: [方法] + [url] + [版本]
Header: 请求的属性, 冒号分割的键值对;每组属性之间使用\n分隔;遇到空行表示Header部分结束。
Body: 空行后面的内容都是Body. Body允许为空字符串. 如果Body存在, 则在Header中会有一个Content-Length属性来标识Body的长度。
响应:
首行:[版本号] + [状态码] + [状态码解释]
Header:请求的属性, 冒号分割的键值对;每组属性之间使用\n分隔;遇到空行表示Header部分结束
Body:空行后面的内容都是Body. Body允许为空字符串. 如果Body存在, 则在Header中会有一个Content-Length属性来标识Body的长度; 如果服务器返回了一个html页面, 那么html页面内容就是在body中。
常见Header:
Content-Type:数据类型(text/html等)
Content-Length: Body的长度
Host:客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
User-Agent:声明用户的操作系统和浏览器版本信息;
referer:当前页面是从哪个页面跳转过来的;
location:搭配3xx状态码使用, 告诉客户端接下来要去哪里访问;
Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;
HTTP的一些方法
表单:收集用户数据,并把用户数据推送给服务器。表单中的数据,会被转成http requst的的一部分。表单一般是需要被提交的,指明提交方法(GRET/POST)。
-
GET方法通过URL向服务端传参,会回显输入的私密信息,不够私密。
-
POST方法通过http正文提交参数。不会回显,私密性有保证。
私密 ≠ 安全,只是明文看不到。
HTTP状态码
最常见的状态码, 比如 200(OK), 404(Not Found), 403(Forbidden), 302(Redirect, 重定向), 504(Bad Gateway)。
重定向:当我们进行某些网页请求时,因为功能要求请求登陆其他页面或者网站。
永久重定向(301):影响用户后续的请求策略。
临时重定向(302、307):不影响用户后续的请求策略。
Http的特征
- 简单快速
- 无连接
- 无状态,并不会记录用户历史或者上一次请求
什么可以用来保存记录用户信息?cookie。
cookie
- cookie文件:保存用户信息。分为文件级cookie与内存级cookie。
- Set-Cookie:"Set-Cookie"响应头用于服务器向客户端发送cookie。它用于在客户端设备上存储信息,可用于各种目的,如会话管理、用户跟踪和个性化。
- cookie的存在,导致http网络存在安全风险。
Connection
- Connection:keep-alive,长链接,可以放多个请求。
- Connection:close,短链接,处理完成一次请求后直接关闭。
HTTPS
HTTPS是什么
HTTP协议内容都是按照文本的方式明文传输的,这就导致在传输过程中,出现一些被篡改的情况。
HTTPS也是一个应用层协议,是HTTP协议的基础上引入了一个加密层。
加密与解密
因为http的内容是明文传输的,明文数据会经过路由器、wifi热点、通信服务运营商、代理服务器等多个物理节点,如果信息在传输过程中被劫持,传输的内容就完全暴露了。劫持者还可以篡改传输的信息且不被双方察觉,这就是中间人攻击
,所以我们才需要对信息进行加密。
加密就是把明文(要传输的信息)进行一系列变换,生成密文。
解密就是把密文再进行一系列变换,还原成明文。
在这个加密和解密的过程中,往往需要一个或者多个中间的数据,辅助进行这个过程,这样的数据称为密钥。
加密与解密到如今已经发展成一个独立的科学:密码学。密码学的奠基人,艾伦·麦席森·图灵。
常见的加密方式
对称加密
- 采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密,特征:加密和解密所用的密钥是相同的。
- 常见对称加密算法:DES、3DES、AES、TDEA、Blowfish、RC2等
- 特点:算法公开、计算量小、加密速度快、加密效率高
举个栗子,一个简单的对称密钥,按位异或:
非对称加密
- 需要两个密钥来进行加密和解密,这两个密钥是公开密钥(public key,简称公钥)和私有密钥(private key,简称私钥)。
- 常见非对称加密算法(了解):RSA,DSA,ECDSA
- 特点:算法强度复杂、安全性依赖于算法与密钥但是由于其算法复杂,而使得加密解密速度没有对称加密解密的速度快。
钥和私钥是配对的,最大的缺点就是运算速度非常慢,比对称加密要慢很多
什么是数据摘要
对原始数据进行哈希散列,生成固定的散列值,这个散列值是唯一存在的,叫做该原始数据的数据摘要。
哈希散列是不可逆的,因此数据摘要不能进行解密,即数据摘要不是加密。
什么是证书
原始数据,通过哈希散列->,固定的散列值(数据摘要),通过签名者(CA机构)的私钥加密->签名。
原始数据+签名->证书
不直接加密形成签名,要先hash形成摘要的原因:
- 缩小签名密文的长度,加快数字签名的验证签名的运算速度
HTTPS如何安全握手
非对称加密+对称加密+证书认证:
证书认证:客户端使对证书内的原始数据使用哈希散列,生成固定散列值,用内置的CA机构公钥进行解密,与证书内的签名进行对比。
中间人篡改替换的方法:ARP欺骗、ICMP攻击、假wifi&&假网站等。
HTTPS工作过程中涉及到的密钥有三组:
-
第一组(非对称加密):用于校验证书是否被篡改。服务器持有私钥(私钥在形成CSR文件与申请证书时获得),客户端持有公钥(操作系统包含了可信任的CA认证机构有哪些,同时持有对应的公钥)。服务器在客户端请求是,返回携带签名的证书。客户端通过这个公钥进行证书验证,保证证书的合法性,进一步保证证书中携带的服务端公钥权威性。
-
第二组(非对称加密):用于协商生成对称加密的密钥。客户端用收到的CA证书中的公钥(是可被信任的)给随机生成的对称加密的密钥加密,传输给服务器,服务器通过私钥解密获取到对称加密密钥.
-
第三组(对称加密):客户端和服务器后续传输的数据都通过这个对称密钥加密解密。
其实一切的关键都是围绕这个对称加密的密钥,其他的机制都是辅助这个密钥工作的。第二组非对称加密的密钥是为了让客户端把这个对称密钥传给服务器, 第一组非对称加密的密钥是为了让客户端拿到第二组非对称加密的公钥。