目录
1. HTTP协议
1.1. http协议
HTTP协议是超文本传输协议的缩写,是用于从万维网服务器传输超文本到本地浏览器的传送协议。 (超文本是用超链接的方法,将各种不同空间的文字信息组织在一起的网状文本)
HTTP是一个基于TCP/IP通信协议来传递数据(HTML文件,图片文件,查询结果等)
HTTP是一个属于应用层的面向对象的协议,工作于客户端-服务器端架构为上。
浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接受到请求后,向客户端发送响应信息。
1.2. HTTP特点:
-
无状态:协议对客户端没有状态存储,对事物处理没有“记忆”能力,比如访问一个网站需要反复进行登录操作
-
无连接:HTTP/1.1之前,由于无状态特点,每次请求需要通过TCP三次握手四次挥手,和服务器重新建立连接。比如某个客户机在短时间多次请求同一个资源,服务器并不能区别是否已经响应过用户的请求,所以每次需要重新响应请求,需要耗费不必要的时间和流量。
-
基于请求和响应:基本的特性,由客户端发起请求,服务端响应
-
简单快速、灵活
-
通信使用明文、请求和响应不会对通信方进行确认、无法保护数据的完整性
1.3. http协议的格式
http无论是请求还是响应,基本上都是按照行为单位进行构建请求或响应的。
其中请求行(状态行)和请求报头(响应报头)被统称为http报头,而请求正文(响应正文)被称为有效载荷。
问题1:http如何封装,如何解包,如何分用?
用空行可以将http请求或响应一分为二(即报头和正文),至于分用问题不是http解决的,是具体的应用代码解决。
问题2:http的request和response如何被看待?(即如何被读取和发送)
实现一个简易的http:
http.cc:
#include"sock.hpp"
#include<pthread.h>
void Usage(string pro)
{
cout << "Usage: " << pro << "port" << endl;
}
void* HandlerHttpRequest(void* arg)
{
int sock = *(int*)arg;
delete (int *)arg;
pthread_detach(pthread_self());
#define SIZE 1024*10
char buffer[SIZE];
memset(buffer, 0, sizeof(buffer));
// 这里的读取部分实际上是有错误的
ssize_t s = recv(sock, buffer, sizeof(buffer), 0);
if(s > 0)
{
buffer[s] = 0;
cout << buffer << endl;
}
close(sock);
return nullptr;
}
int main(int argc, char* argv[])
{
if(argc != 2)
{
Usage(argv[0]);
exit(1);
}
uint16_t port = atoi(argv[1]);
int listen_sock = Sock::Socket();
Sock::Bind(listen_sock, port);
Sock::Listen(listen_sock);
while(true)
{
int sock = Sock::Accept(listen_sock);
if(sock > 0)
{
pthread_t tid;
int *parm = new int(sock);
pthread_create(&tid, nullptr, HandlerHttpRequest, parm);
}
}
return 0;
}
sock.hpp
#pragma once
#include<iostream>
#include<string>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdlib.h>
#include<cstring>
using namespace std;
class Sock
{
public:
static int Socket()
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0)
{
cerr << "socket error" << endl;
exit(2);
}
return sock;
}
static void Bind(int sock, uint16_t port)
{
struct sockaddr_in local;
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = INADDR_ANY;
if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
{
cerr << "bind error" << endl;
exit(3);
}
}
static void Listen(int sock)
{
if(listen(sock, 5) < 0)
{
cerr << "listen error" << endl;
exit(4);
}
}
static int Accept(int sock)
{
struct sockaddr_in peer;
socklen_t len = sizeof(peer);
int fd = accept(sock, (struct sockaddr *)&peer, &len);
if(fd >= 0)
{
return fd;
}
return -1;
}
static void Connect(int sock, string ip , uint16_t port)
{
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ip.c_str());
if(connect(sock, (struct sockaddr*)&server, sizeof(server)==0))
{
cout << "connect success!" << endl;
}
else
{
cout << "connect failed" << endl;
exit(5);
}
}
};
这里可以发现,其实http的底层就是tcp。
运行后,通过网页发送http请求:
由于我们这个请求太简单了。很多信息都没有。
Content-Length:如果有正文,包头部分就会有这个属性,其表示正文部分的字节数,根据Conten-Length就可以将有效载荷全部读取。
空行:其意义在于:a.读取http报文时,读到空行即表示已经将报头部分全部读完;b.将报头和正文分离。
1.4. http的请求方法
短链接:一个请求,一个响应,然后close socket
http请求的“/”不是根目录,而是web根目录。一般请求的是一个具体的资源。
但如果请求的是“/”,服务器内部会自动请求该网站的首页信息(一般为index.html)。
GET方法,如果提交参数,是通过url方式进行提交的。
POST方法,如果提交参数,是通过正文进行提交的。
GET:获取,是最常用的方法,默认一般获取所有的网页,都是使用GET方法,但是如果GET要提交参数,要通过URL来进行参数拼接,从而提交给server端。
POST:推送,是提交参数比较常用的方法,一般通过正文提交。
区别:
参数提交的位置不同,POST方法比较私密(私密 != 安全),不会回显到浏览器的url输入框。
GET是通过url传参的,而url是有大小限制的,和具体浏览器有关。POST方法是由正文部分传参,一般大小没有限制。
如何选择:
如果提交的参数,不敏感,数量非常少,可以采用GET。
否则采用POST。
1.5. http状态码
http响应的第一行(状态行)会有一个数字,就是状态码,例如: http/1.0 200 ok\n
常见的状态码:200,404,501等。
重定向:当访问一个网站的时候,会跳转到另一个网址(老网站过期,跳转到新网站),或者是访问网站时,提示登陆,然后跳转到登录页面,登陆后自动跳转会原来的页面,像这些现象就是重定向。
301永久重定向:例如某平台更换网站时,为了不损失老用户,当老用户访问老网站时,该浏览器会向新网站重新发起请求,就会跳转至新网站,而用户书签中的老网站的域名也会被替换为新网站的域名。
302、307临时重定向:跳转登录,登陆后再跳转至原页面。
上述重定向状态码,需要浏览器提供支持,server要告诉浏览器应该跳转到哪里。
而http报头中的Location就起到这个作用。
1.6. http常见Header
Content-Type: 数据类型(text/html等)
Content-Length: Body的长度
Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
User-Agent: 声明用户的操作系统和浏览器版本信息;
referer: 当前页面是从哪个页面跳转过来的;
location: 搭配3xx状态码使用, 告诉客户端接下来要去哪里访问;
Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能 ;
1.7. 长短链接
http / 1.0 采用的网络请求的方案是短链接,即request->response->close(一个请求对应一个响应然后关闭链接)。
访问一个由多个元素构成的网页的时候,http / 1.0 就需要进行多次http请求,http协议是基于tcp协议的,tcp通信就需要建立连接、传输数据、断开链接,每一次的http request都要执行上面的过程。效率比较低。
http / 1.1 支持长连接,通过减少频繁建立tcp链接,来达到提高效率的目的。
为了确定client和server双方是否都支持长连接,在http报头的属性中有一个Connection表示是否支持。keep-alive表示支持,close表示不支持。
1.8. Cookie和session
1.8.1. Cookie是什么
Cookie是由服务器端生成,发送给User-Agent,浏览器会将Cookie的key/value自动保存到某个目录下的文本文件内,下次请求同一网站时就自动发送该Cookie给服务器。
在浏览器角度:Cookie其实是一个文件,该文件里保存的是用户的私密信息。
在http协议角度:一旦该网站有对应Cookie,在发起任何请求的时候,都会自动在request中携带该Cookie信息。
目前Cookie已经成为标准,所有的主流浏览器如IE、Netscape、Firefox、Opera等都支持Cookie。
cookie默认根据域名自动判断是否带上cookie信息访问。
1.8.2. Cookie 应用场景
场景一:避免重复登录
当我们打开一个网站时,如果这个网站我们曾经登录过,那么当我们再次打开网站时,发现就不需要再次登录了,而是直接进入了首页(例如:csdn)。
场景二:权限验证
由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。
ps:http无状态:http不知道上一次访问该网站的用户是谁,不会记录http请求的上下文信息。
通过Set-Cookie报头属性可以向浏览器写入Cookie信息。
1.8.3. cookie特点
-
Cookie的不可跨域名性
-
cookie会被附加在每个HTTP请求中,所以无形中增加了流量。
-
由于在HTTP请求中的cookie是明文传递的,所以安全性成问题。(除非用HTTPS)
-
Cookie的大小限制在4KB左右。对于复杂的存储需求来说是不够用的。
由于Cookie有大小限制而且存在一定的安全隐患:1.别人盗取自己的Cookie文件,可以以我的身份进行认证访问特定资源;2.如果Cookie中保存了,用户名和密码,那么自己的账号可能会被盗取。
所以就有了session,即将用户的私密信息保存在服务器端。
1.8.4. session是什么
session在网络应用中称为“会话控制”,是服务器为了保存用户状态而创建的一个特殊的对象。简而言之,session就是一个对象,用于存储信息。
我们可以通过一张图片来解释:
虽然session并不能有效的防止信息泄露,但是衍生出了一些防御措施,例如通过常用ip地址判定用户账号是否存在异常。如果存在异常地址登录,服务器则会废弃掉当前的session_id,让用户重新认证登录。
Cookie+session 的本质:提高用户访问网站或者平台的体验。
1.8.5. session和cookie的比较
-
cookie保存在客户端,session保存在服务端
-
cookie作用于他所表示的path中(url中要包含path),范围较小。session代表客户端和服务器的一次会话过程,web页面跳转时也可以共享数据,范围是本次会话,客户端关闭也不会消失。会持续到我们设置的session生命周期结束(默认30min)
-
我们使用session需要cookie的配合。cookie用来携带JSESSIONID
-
cookie存放的数据量较小,session可以存储更多的信息。
-
cookie由于存放在客服端,相对于session更不安全
-
由于session是存放于服务器的,当有很多客户端访问时,肯定会产生大量的session,这些session会对服务端的性能造成影响。
2. https
2.1. https是什么
基于HTTP协议,通过SSL或TLS提供加密处理数据、验证对方身份以及数据完整性保护。
通过抓包可以看到数据不是明文传输,而且HTTPS有如下特点:
-
内容加密:采用混合加密技术,中间者无法直接查看明文内容
-
验证身份:通过证书认证客户端访问的是自己的服务器
-
保护数据完整性:防止传输的内容被中间人冒充或者篡改
2.2. 加密方式
混合加密:结合非对称加密和对称加密技术。客户端使用对称加密生成密钥对传输数据进行加密,然后使用非对称加密的公钥再对秘钥进行加密,所以网络上传输的数据是被秘钥加密的密文和用公钥加密后的秘密秘钥,因此即使被黑客截取,由于没有私钥,无法获取到加密明文的秘钥,便无法获取到明文数据。
-
对称加密:密钥(只有一个)X,即用X加密也用X解密。
-
非对称加密:有一对密钥,公钥和私钥,可以用公钥加密,但是只能用私钥解密;或者用私钥加密,只能用公钥解密。一般而言,公钥是全世界公开的,私钥必须自己进行私有保存的。
数字摘要:通过单向hash函数对原文进行哈希,将需加密的明文“摘要”成一串固定长度(如128bit)的密文,不同的明文摘要成的密文其结果总是不相同,同样的明文其摘要必定一致,并且即使知道了摘要也不能反推出明文。
数字签名技术:数字签名建立在公钥加密体制基础上,是公钥加密技术的另一类应用。它把公钥加密技术和数字摘要结合起来,形成了实用的数字签名技术。
大概过程:
生活中的数据传输一般是混合加密技术,即对称加密和非对称加密结合使用。
其大概过程为:
ps:网络中通信的数据别人是可以拿到的,所以所谓的数据安全,不是让别人拿不到,而是别人拿到了也无法处理。
2.3. 中间人攻击
但是这个过程也不能保证百分之百的安全,通过中间人对S公钥的截取,修改服务器发送给客户端的公钥,客户端通过这个公钥加密形成的私钥后,中间人就可以获取到私钥并且能解开,然后将私钥按照原本的加密方式加密,这样服务器还能通过原来的私钥解密得到对称加密的私钥,中间人就能神不知鬼不觉的窃取后续通信数据。
如图:
而上述问题的解决方案是通过证书来解决。
CA机构:
CA中心又称CA机构,即证书授权中心(Certificate Authority ),或称证书授权机构,作为电子商务交易中受信任的第三方,承担公钥体系中公钥的合法性检验的责任。CA中心为每个使用公开密钥的用户发放一个数字证书,数字证书的作用是证明证书中列出的用户合法拥有证书中列出的公开密钥。CA机构的数字签名使得攻击者不能伪造和篡改证书。在SET交易中,CA不仅对持卡人、商户发放证书,还要对获款的银行、网关发放证书。它负责产生、分配并管理所有参与网上交易的个体所需的数字证书,因此是安全电子交易的核心环节。