网络应用层HTTP/HTTPS
引入
协议是一种 “约定”. socket api的接口, 在读写数据时, 都是按 “字符串” 的方式来发送接收的. 那么如何传输一些"结构化的数据" 呢?
例如
:结构化的数据转为string可以用jsoncpp,XML等等(方便传输不出错
)
自定义协议
:双方约定好一种结构化的数据
应用层协议
:只要保证, 一端发送时构造的数据, 在另一端能够正确的进行解析, 就是可以的. 这种约定, 就是 应用层协议
HTTP
早期程序员定义了一些现成的, 又非常好用的应用层协议, 供我们直接参考使用. HTTP(超文本传输协议)就是其中之一
对于http协议
:大部分应用层协议(高频的)都不用自己写,少数需要自己写
http协议
:是一个应用层协议,底层是tcp协议! http要 用tcp来完成数据通信的能力(socket编程)
1)URL
结构
2)urlencode urldecode
/
?
:
等这样的字符, 已经被url当做特殊意义理解了. 因此这些字符不能随意出现,某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义.
转义的规则
: 将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式
3)HTTP协议格式
简易的http服务器:
部分代码如下:static void* Handler(void* args)//类中创建线程要static { pthread_detach(pthread_self()); int sock = *(int*)args;//先强转为int*再解引用 delete (int*)args;//??为什么要强转 char buffer[4096]; ssize_t s=recv(sock, buffer, sizeof(buffer), MSG_WAITALL); if(s>0) { cout<<buffer<<endl; } close(sock); return nullptr; }
可以注意到
:都是以行为单位,进行消息内容的陈列其中除了 第一行,默认每行都是name: value 的样式,并且结尾有空行
①http请求格式
每层协议都要解决两个问题:
- 将报头和有效载荷分离
- 将自己的有效载荷交付给上层协议
空行
作为一个特殊符号,来表明http请求报头的结束
请求方法:
请求方法 说明 HTTP协议版本 GET 获取资源 1.0、1.1 POST 传输实体主体 1.0、1.1 PUT 传输文件 1.0、1.1 HEAD 获得报文首部 1.0、1.1 DELETE 删除文件 1.0、1.1 OPTIONS 询问支持的方法 1.1 TRACE 追踪路径 1.1 CONNECT 要求用隧道协议连接代理 1.1 LINK 建立和资源之间的联系 1.0 UNLINE 断开连接关系 1.0
POST方法通常用来提交参数,参数会以http请求的正文方式进行提交
GET 比较 POST
- POST提交更具有私密性
- GET和POST方法 都不安全,因为默认都没有加密
- .提交的数据可以很大
- Get通常 用来进行获取网页等资源,不过也可以提交参数:百度搜索
- . POST通常 用来提交数据
常见报头:
- Content-Type: 数据类型(text/html等)
- Content-Length: Body的长度
- Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
- User-Agent: 声明用户的操作系统和浏览器版本信息;
- referer: 当前页面是从哪个页面跳转过来的;
- location: 搭配3xx状态码使用, 告诉客户端接下来要去哪里访问;
- Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;
②http响应格式
格式和请求相似
常见状态码
:200(OK), 404(Not Found), 403(Forbidden), 302(Redirect, 重定向), 504(Bad Gateway)
类别 原因短语 1XX Informational (信息性状态码) 接收的请求正在处理 2XX Success (成功状态码) 请求正常处理完毕 3XX Redirection (重定向状态码) 需要进行附加操作以完成请求 4XX Client Error (客户端错误状态码) 服务器无法处理请求 5XX Server Error (服务器错误状态码) 服务器处理请求出错
测试301(永久重定向)
status_line += (" " + std::to_string(301) + " Moved Permanently\n"); std::string response_header = "Content-Type: text/html;charset=utf8\n"; response_header += "location: https://www.baidu.com/\n" ; response_header += "\n"; send(sock, status_line.c_str(), status_line.size(), 0); send(sock,response_header.c_str(), response_header.size(), 0);
永久重定向和临时重定向区别:
永久
:抓取新内容的同时,将之前的旧抓取地址更新成重定向后的地址(301)临时
:抓取新的内容的时候,保留旧的地址,因为当前的重定向只是暂时的,很快就会恢复旧地址的访问(302 307)
可以将请求和响应均看作一个包含诸多\n的长字符串
返回响应内容:std::ifstream in("./index.html", std::ios::in | std::ios::binary); if(!in.is_open()) else{//成功 std::string line; while(std::getline(in, line)) body+=line; response = "HTTP/1.0"; response += " 200 OK\n"; response += "Content-Type: text/html\n"; response += ("Content-Length: " + std::to_string(body.size()) + "\n"); response += "\n"; //空行,用来区分我们的报头和有效载荷 response += body; } in.close();
4)cookie/session
①cookie
http性质:
- http本身是无连接的(底层基于TCP协议,http要发起http request时,不会在http层建立连接)
- http本身时无状态的(不会记录自己发起http请求的上下文,不会对历史请求有任何记忆能力)
- http发起连接有基于长连接也有基于短连接
为了让http具有保存状态的能力和会话能力,有了cookie和session
cookie可以弥补HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话
将你保存的账号密码等私密信息保存在浏览器的默认文件中(cookie),浏览器每次发送请求时 http都会自动为你携带曾经写到临时文件中的内容发送给服务器
当浏览器使用cookie时:
- 每个http request都会携带cookie的信息,发送给服务器(需要服务器支持cookie技术,cookie技术不是http完成的,而是程序员完成)
- cookie文件在浏览器配置的时候有
内存级cookie
(重启后丢失),和文件级cookie
(重启后仍然在)
cookie风险:
- cookie可以泄漏个人私密信息(明文密码…)
- 使用你的cookie可以直接用你的身份向server发起请求
②cookie+session
使用cookie+session来维持会话:
session存储在serer端,文件名具有唯一性,
代码验证:response += "Set-Cookie:Session_id=3jkdf3847sfs7f7dferr2\n";
第一次server端responed(带上cookie)
:
以后每次client会带上这个cookie请求
:
sever端进行sessionid比对 1.成功允许查看敏感资源 失败禁止访问
session与cookie的比较:
(摘自:https://blog.csdn.net/DUANJIAWEIDUANJIAWEI/article/details/118608668)
1、cookie和session都是服务端生成的,只是cookie存放在客户端,session存放在服务端
2、cookie是不安全的,黑客可以通过抓包获取用户信息,session是安全的因为存放在服务器
3、session因为存放在服务端,当session数量比较多时会占用一定的内存空间造成服务器性能低
4、单个cookie的大小是4k, 很多浏览器限制一个站点最多保存20个cookie,而session保存在服务端没有大小限制
5、cookie和session都会有时间限制,即都会过期
6、session的使用依赖cookie,会把JSESSIONID保存在cookie里面
5)https
①http与https的安全性
http的GET和POST请求均不安全:
GET
:直接显示在URL中
POST
: 仍然可以看到
http和https的区别:
https加上了加密解密的软件层,这里所谓的加密解密的软件层,本质是在用户层
SSL
(Secure Sockets Layer)TLS
(Transport Layer Security,传输层安全)
SSL也是分层,两层
- 封装加密解密
- https握手(确保安全性)
②对称与非对称加密
对称加密
:(只有一个秘钥,例如a^5=b,b^5=a,异或运算可以看为一种对称加密)
非对称加密
(公钥和私钥, md5, RSA 非对称加密中,一 般公钥是公开的,私钥必须保存)
- 公钥:公钥用来给数据加密,用公钥加密的数据只能使用私钥解密
- 私钥:用来解密公钥加密的数据
md5:
- 摘要:hash算法,提取出文本中的部分内容
- md5=摘要+特定的加密(md5一般为16字节)
数据指纹
:凡是对原始文本做任何修改,在进行摘要形成指纹之后,得到的指纹数据,差别会非常大
有的公司还会使用加盐
:“明文密码”+salt->md5()->数据库
http刚开始通信的时候,绝对不能使用对称加密,第一次交换秘钥就会出现鸡生蛋蛋生鸡的问题(加解密获取密钥先后关系)
公钥A只能由私钥A解密,公钥B只能由私钥B解密,保证单向安全性
由于非对称加密效率极低,前期ssl握手期间,使用非对称加密,来交换对称加密的秘钥,通信期间,采用对称加密来保证数据安全
③https密钥协商
https密钥协商(非对称) 和 加密通信(对称)
密钥协商过程:
- https向server发起https请求(server端已有公钥和独有的私钥)
- server将公钥发给client,client生成随机对称密钥D,再使用server发的公钥加密,形成密文,将这个加密后的密钥D发给server
- server使用已有的私钥对密钥D进行解密得到密钥D
加密通信:
- 之后的通信,client就可以使用对称密钥D加密,server就可以使用对称密钥D解密 (注意:对称密钥也是数据,也可以被加密)
中间人攻击获取密钥
上面的方式并不安全
中间人攻击:
过程:
- client向server发送https请求(server有公钥A 私钥a)
- server向client发送公钥A(此时公钥被中间人截获,保留A并将A替换为自己的公钥M,发送给client)
- client并不知道公钥被更改,继续使用公钥M进行生成对称密钥D,同时用公钥M加密,将密文发给server
- 中间人再次截获,使用私钥m解密得到对称密钥D,再次使用保留的server公钥A对D进行加密,发送给server
- server正常得到对称密钥D
之后的通信都会经过中间人(中间人可随意修改)
对于加密通信阶段中间人是不能进行信息篡改的:
- 中间人不能篡改信息(没有密钥)
- 当尝试破坏的时候,server端使用对称密钥会解不开->发现中间人
证书机制
为防止中间人攻击,如何确保对方发来的公钥没有被篡改过---------->权威机构对网站或服务器进行合法认证(
CA认证
)
client发起https请求时,server会将证书(公钥,和其他信息)发给client
CA证书形成
:(CA机构也有自己的公钥和私钥)
在申请证书的时候需要提供server的公钥(server不能在发送给client的时候再篡改证书(没有CA私钥))
- 证书内容(时间,颁发人等)文本信息,进行hash算法形成摘要
- 将摘要进行加密(使用CA的私钥),形成指纹,将指纹添加到证书中
client判断证书
:
- 证书是否合法
- 如何证明证书没有被篡改过(通过对比原文摘要和指纹携带的摘要是否一致来判断)
client如何获得CA的公钥
:
- OS以及浏览器出厂的时候就内置了各种权威机构认证证书
中间人想要篡改证书:
- 对明文内容篡改 + 再用自己的非对称加密算法形成指纹(
不成立,client总是使用CA公钥进行解密,发现不能用CA公钥解密的判定被篡改
)- 中间人申请合法证书 (
证书包含了域名,当替换证书的时候client会发现域名问题,同时中间人会保留自己的域名
)
总结:为什么携带了指纹的证书不怕被修改:
- 任何中间人都没有当时形成指纹的CA私钥
- 在client认证阶段,client只会只用CA的公钥来进行证书认证,不相信任何人的其他公钥信息
DNS
摘要:
TCP/IP中使用IP地址和端口号来确定网络上的一台主机的一个程序.
但是IP地址不方便记忆.于是人们发明了一种叫主机名的东西, 是一个字符串, 并且使用hosts文件来描述主机名和IP地址的关系
最初, 通过互连网信息中心(SRI-NIC)来管理这个hosts文件的.
- 如果一个新计算机要接入网络, 或者某个计算机IP变更, 都需要到信息中心申请变更hosts文件.
- 其他计算机也需要定期下载更新新版本的hosts文件才能正确上网.
这样就太麻烦了, 于是产生了DNS系统.
- 一个组织的系统管理机构, 维护系统内的每个主机的IP和主机名的对应关系
- 如果新计算机接入网络, 将这个信息注册到数据库中;
用户输入域名的时候, 会自动查询DNS服务器, 由DNS服务器检索数据库, 得到对应的IP地址
通过cat /etc/hosts命令查看hosts信息
www.example.com
域名使用 . 连接
- com: 一级域名. 表示这是一个企业域名. 同级的还有 “net”(网络提供商), “org”(非盈利组织) 等.
- example: 二级域名, 公司名.
- www: 只是一种习惯用法. 之前人们在使用域名时, 往往命名成类似于ftp.xxx.xxx/www.xxx.xxx这样的格式, 来表示主机支持的协议