这里主要讲应用层协议
应用层的常见协议
- 超文本传输:HTTP、HTTPS
- 文件传输:FTP
- 电子邮件:SMTP、POP3、IMAP
- 动态主机配置:DHCP
- 域名系统:DNS
域名(Domain Name)
由于IP地址不方便记忆,并且不能表达组织的名称和性质,人们设计出了域名(比如baidu.com)
根据级别不同,域名可以分为
顶级域名的分类
通用顶级域名(General Top-level Domain,简称gTLD)
二级域名
二级域名是指顶级域名之下的域名 在通用顶级域名下,它一般指域名注册人的名称,例如google、baidu、microsoft等 在国家及地区顶级域名下,它一般指注册类别的,例如com、edu、gov、net等
DNS
DNS的全称是:Domain Name System,译为:域名系统
利用DNS协议,可以将域名(比如baidu.com)解析成对应的IP地址(比如220.181.38.148)
DNS可以基于UDP协议,也可以基于TCP协议,服务器占用53端口
DNS特点
客户端首先会访问最近的一台DNS服务器(也就是客户端自己配置的DNS服务器) 所有的DNS服务器都记录了DNS根域名服务器的IP地址 上级DNS服务器记录了下一级DNS服务器的IP地址 全球一共13台IPv4的DNS根域名服务器、25台IPv6的DNS根域名服务器
DNS常用命令
ipconfig /displaydns:查看DNS缓存记录 ipconfig /flushdns:清空DNS缓存记录 ping 域名 nslookup 域名
IP分配方式:
IP地址按照分配方式,可以分为:静态IP地址、动态IP地址静态IP地址 手动设置 适用场景:不怎么挪动的台式机(比如学校机房中的台式机)、服务器等动态IP地址 从DHCP服务器自动获取IP地址 适用场景:移动设备、无线设备等
DHCP协议
DHCP(Dynamic Host Configuration Protocol),译为:动态主机配置协议 DHCP协议基于UDP协议,客户端是68端口,服务器是67端口 DHCP服务器会从IP地址池中,挑选一个IP地址“出租“给客户端一段时间,时间到期就回收它们。平时家里上网的路由器就可以充当DHCP服务器
DHCP的四个阶段
DISCOVER:发现服务器
发广播包(源IP是0.0.0.0,目标IP是255.255.255.255,目标MAC是FF:FF:FF:FF:FF:FF)OFFER:提供租约
服务器返回可以租用的IP地址,以及租用期限、子网掩码、网关、DNS等信息
注意:这里可能会有多个服务器提供租约
REQUEST:选择IP地址
客户端选择一个OFFER,发送广播包进行回应ACKNOWLEDGE:
确被选中的服务器发送ACK数据包给客户端
至此,IP地址分配完毕
细节:
DHCP服务器可以跨网段分配IP地址么?(DHCP服务器、客户端不在同一个网段)
可以借助DHCP中继代理(DHCP Relay Agent)实现跨网段分配IP地址自动续约
客户端会在租期不足的时候,自动向DHCP服务器发送REQUEST信息申请续约常用命令
- ipconfig /all:可以看到DHCP相关的详细信息,比如租约过期时间、DHCP服务器地址等
- ipconfig /release:释放租约
- ipconfig /renew:重新申请IP地址、申请续约(延长租期)
HTTP协议
HTTP(Hyper Text Transfer Protocol),译为超文本传输协议
历史版本
1991年,HTTP/0.9 只支持GET请求方法获取文本数据(比如HTML文档),且不支持请求头、响应头等,无法向服务器传递太多信息 支持POST、HEAD等请求方法,支持请求头、响应头等,支持更多种数据类型(不再局限于文本数据) 浏览器的每次请求都需要与服务器建立一个TCP连接,请求处理完成后立即断开TCP连接 支持PUT、DELETE等请求方法 采用持久连接(Connection: keep-alive),多个请求可以共用同一个TCP连接 2015年,HTTP/2.0 2018年,HTTP/3.0
HTTP的标准
HTTP的标准 由万维网协会(W3C)、互联网工程任务组(IETF)协调制定,最终发布了一系列的RFC RFC(Request For Comments,可以译为:请求意见稿 HTTP/1.1最早是在1997年的RFC 2068中记录的 该规范在1999年的RFC 2616中已作废 2014年又由RFC 7230系列的RFC取代 HTTP/2标准于2015年5月以RFC 7540正式发表,取代HTTP/1.1成为HTTP的实现标准 中国的RFC 1996年3月,清华大学提交的适应不同国家和地区中文编码的汉字统一传输标准被IETF通过为RFC 1922 成为中国大陆第一个被认可为RFC文件的提交协议
报文的基本格式
ABNF
ABNF(Augmented BNF) 是BNF(Backus-Naur Form,译为:巴科斯-瑙尔范式)的修改、增强版 在RFC 5234中表明:ABNF用作internet中通信协议的定义语言 ABNF是最严谨的HTTP报文格式描述形式,脱离ABNF谈论HTTP报文格式,往往都是片面、不严谨的 关于HTTP报文格式的定义 RFC 2616 4.HTTP Message(旧) RFC 7230 3.Message Format(新)
ABNF - 核心规则
符合规范的报文格式
// requesst-line status-line
request-line = method SP request-target SP HTTP-version CRLF
HTTP-version = HTTP-name "/" DIGIT "." DIGIT
HTTP-name = %x48.54.54.50 ; HTTP
status-line = HTTP-version SP status-code SP reason-phrase CRLF
status-code = 3DIGIT
reason-phrase = *( HTAB / SP / VCHAR / obs-text )
// header-filed message-body
header-field = field-name ":" OWS field-value OWS
field-name = token
field-value = *( field-content / obs-fold)
OWS = *( SP / HTAB )
message-body = *OCTET
请求方法
RFC 7231, section 4: Request methods:描述了8种请求方法 GET、HEAD、POST、PUT、DELETE、CONNECT、OPTIONS、TRACE RFC 5789, section 2: Patch method:描述了PATCH方法 GET:常用于读取的操作,请求参数直接拼接在URL的后面(浏览器对URL是有长度限制的) POST:常用于添加、修改、删除的操作,请求参数可以放到请求体中(没有大小限制) HEAD:请求得到与GET请求相同的响应,但没有响应体 使用场景举例:在下载一个大文件前,先获取其大小,再决定是否要下载。以此可以节约带宽资源 OPTIONS:用于获取目的资源所支持的通信选项,比如服务器支持的请求方法 OPTIONS * HTTP/1.1 PUT:用于对已存在的资源进行整体覆盖 PATCH:用于对资源进行部分修改(资源不存在,会创建新的资源) DELETE:用于删除指定的资源 TRACE:请求服务器回显其收到的请求信息,主要用于HTTP请求的测试或诊断 CONNECT:可以开启一个客户端与所请求资源之间的双向沟通的通道,它可以用来创建隧道(tunnel) 可以用来访问采用了 SSL (HTTPS) 协议的站点
头部字段
头部字段可以分为4种类型 请求头字段(Request Header Fields) 有关要获取的资源或客户端本身信息的消息头 响应头字段(Response Header Fields) 有关响应的补充信息,比如服务器本身(名称和版本等)的消息头 实体头字段(Entity Header Fields) 有关实体主体的更多信息,比如主体长度(Content-Length)或其MIME类型 通用头字段(General Header Fields) 同时适用于请求和响应消息,但与消息主体无关的消息头
请求头字段
响应头字段
状态码
状态码指示HTTP请求是否已成功完成
状态码可以分为5类 信息响应:100~199 100 Continue
- 请求的初始部分已经被服务器收到,并且没有被服务器拒绝。客户端应该继续发送剩余的请求,如果请求已经完
- 允许客户端发送带请求体的请求前,判断服务器是否愿意接收请求(服务器通过请求头判断)
- 在某些情况下,如果服务器在不看请求体就拒绝请求时,客户端就发送请求体是不恰当的或低效的
成功响应:200~299
- 200 OK:请求成功
重定向:300~399
- 302 Found:请求的资源被暂时的移动到了由Location头部指定的URL上
- 304 Not Modified:说明无需再次传输请求的内容,也就是说可以使用缓存的内容
客户端错误:400~499
- 400 Bad Request:由于语法无效,服务器无法理解该请求
- 401 Unauthorized:由于缺乏目标资源要求的身份验证凭证
- 403 Forbidden:服务器端有能力处理该请求,但是拒绝授权访问
- 404 Not Found:服务器端无法找到所请求的资源
- 405 Method Not Allowed:服务器禁止了使用当前HTTP方法的请求
- 406 Not Acceptable:服务器端无法提供与Accept-Charset以及Accept-Language指定的值相匹配的响应
- 408 Request Timeout:服务器想要将没有在使用的连接关闭
- 一些服务器会在空闲连接上发送此信息,即便是在客户端没有发送任何请求的情况下
服务器错误 :500~599
- 500 Internal Server Error:所请求的服务器遇到意外的情况并阻止其执行请求
- 501 Not Implemented:请求的方法不被服务器支持,因此无法被处理,服务器必须支持的方法(即不会返回这个状态码的方法)只有 GET 和 HEAD
- 502 Bad Gateway:作为网关或代理角色的服务器,从上游服务器(如tomcat)中接收到的响应是无效的
- 503 Service Unavailable:服务器尚未处于可以接受请求的状态,通常造成这种情况的原因是由于服务器停机维护或者已超载
文件上传的方式
application/x-www-form-urlencoded(默认值) 用&分隔参数,用=分隔键和值,字符用URL编码方式进行编码multipart/form-data 文件上传时必须使用这种编码方式
缓存(Cache)
- 强缓存
- 协商缓存
URL编码
URL中一旦出现了一些特殊字符(比如中文、空格),需要进行编码 在浏览器地址栏输入URL时,是采用UTF-8进行编码 比如 编码前:www.baidu.com/s?wd=百度 编码后:www.baidu.com/s?wd=%E5%8D…
代理服务器
**特点 ** 本身不生产内容 处于中间位置转发上下游的请求和响应 面向下游的客户端:它是服务器 面向上游的服务器:它是客户端
正向代理与反向代理
正向代理:代理的对象是客户端
正向代理的作用
- 隐藏客户端身份
- 绕过防火墙(突破访问限制)
- Internet访问控制
- 数据过滤
- ......
一些免费的正向代理 ip.jiangxianli.com/ www.kuaidaili.com/free/inha/
反向代理的作用
- 隐藏服务器身份
- 安全防护
- 负载均衡
抓包工作的原理
Fiddler、Charles等抓包工具的原理:在客户端启动了正向代理服务
需要注意的是:Wireshark的原理是:通过底层驱动,拦截网卡上流过的数据
代理服务器 - 相关的头部字段
- Via:追加经过的每一台代理服务器的主机名(或域名)
- X-Forwarded-For:追加请求方的IP地址
- X-Real-IP:客户端的真实IP地址
第一点: X-Forwarded-For: 14.14.14.14 X-Real-IP: 14.14.14.14 Via: proxy1 第二点: X-Forwarded-For: 14.14.14.14, 220.11.11.11 X-Real-IP: 14.14.14.14 Via: proxy1, proxy2 第三点: Via: proxy2 第四点: Via: proxy2, proxy1
cdn
CDN(Content Delivery Network或Content Distribution Network),译为:内容分发网络
利用最靠近每位用户的服务器
更快更可靠地将音乐、图片、视频等资源文件(一般是静态资源)传递给用户
使用cdn的前后比较
CDN运营商在全国、乃至全球的各个大枢纽城市都建立了机房
部署了大量拥有高存储高带宽的节点,构建了一个跨运营商、跨地域的专用网络
内容所有者向CDN运营商支付费用,CDN将其内容交付给最终用户
使用cdn前
使用cdn后
网络安全
网络中面临的四种威胁
- 截获:窃听通信内容
- 中断:中断网络通信
- 篡改:篡改通信内容
- 伪造:伪造通信内容
ARP欺骗
ARP欺骗(ARP spoofing),又称ARP毒化(ARP poisoning)、ARP病毒、ARP攻击 ARP欺骗可以造成的效果 可让攻击者获取局域网上的数据包甚至可篡改数据包 可让网络上特定电脑之间无法正常通信(例如网络执法官这样的软件) 让送至特定IP地址的流量被错误送到攻击者所取代的地方
APR欺骗步骤
假设主机C是攻击者,主机A、B是被攻击者 C只要收到过A、B发送的ARP请求,就会拥有A、B的IP、MAC地址,就可以进行欺骗活动 C发送一个ARP响应给B,把响应包里的源IP设为A的IP地址,源MAC设为C的MAC地址 B收到ARP响应后,更新它的ARP表,把A的MAC地址(IP_A, MAC_A)改为(IP_A, MAC_C) 当B要发送数据包给A时,它根据ARP表来封装数据包的头部,把目标MAC地址设为MAC_C,而非MAC_A 当交换机收到B发送给A的数据包时,根据此包的目标MAC地址(MAC_C)而把数据包转发给C C收到数据包后,可以把它存起来后再发送给A,达到窃听效果。C也可以篡改数据后才发送数据包给A
ARP防护
静态ARP DHCP Snooping,网络设备可借由DHCP保留网络上各电脑的MAC地址,在伪造的ARP数据包发出时即可侦测到 利用一些软件监听ARP的不正常变动
DoS,DDoS攻击
DoS攻击(拒绝服务攻击,Denial-of-Service attack) 使目标电脑的网络或系统资源耗尽,使服务暂时中断或停止,导致其正常用户无法访问 DDoS攻击(分布式拒绝服务攻击,Distributed Denial-of-Service attack) 黑客使用网络上两个或以上被攻陷的电脑作为“僵尸”向特定的目标发动DoS攻击 2018年3月,GitHub遭到迄今为止规模最大的DDoS攻击 DoS攻击可以分为2大类 带宽消耗型:UDP洪水攻击、ICMP洪水攻击 资源消耗型:SYN洪水攻击、LAND攻击
DoS,DDoS 防御
防御方式通常为:入侵检测、流量过滤、和多重验证 防火墙 防火墙可以设置规则,例如允许或拒绝特定通讯协议,端口或IP地址 当攻击从少数不正常的IP地址发出时,可以简单的使用拒绝规则阻止一切从攻击源IP发出的通信 复杂攻击难以用简单规则来阻止,例如80端口遭受攻击时不可能拒绝端口所有的通信,因为同时会阻止合法
流量 防火墙可能处于网络架构中过后的位置,路由器可能在恶意流量达到防火墙前即被攻击影响
交换机:大多数交换机有一定的速度限制和访问控制能力
路由器:和交换机类似,路由器也有一定的速度限制和访问控制能力
黑洞引导 将所有受攻击计算机的通信全部发送至一个“黑洞”(空接口或不存在的计算机地址)或者有足够能力处理洪流的网络设备商,以避免网络受到较大影响
流量清洗 当流量被送到DDoS防护清洗中心时,通过采用抗DDoS软件处理,将正常流量和恶意流量区分开
传输层 - SYN洪水攻击
SYN洪水攻击(SYN flooding attack) 攻击者发送一系列的SYN请求到目标,然后让目标因收不到ACK(第3次握手)而进行等待、消耗资源
攻击方法 跳过发送最后的ACK信息 修改源IP地址,让目标送SYN-ACK到伪造的IP地址,因此目标永不可能收到ACK(第3次握手)
防护 参考:RFC 4987
传输层 LAND攻击
LAND攻击(局域网拒绝服务攻击,Local Area Network Denial attack) 通过持续发送相同源地址和目标地址的欺骗数据包,使目标试图与自己建立连接,消耗系统资源直至崩溃 有些系统存在设计上的缺陷,允许设备接受并响应来自网络、却宣称来自于设备自身的数据包,导致循环应答
防护 大多数防火墙都能拦截类似的攻击包,以保护系统 部分操作系统通过发布安全补丁修复了这一漏洞 路由器应同时配置上行与下行筛选器,屏蔽所有源地址与目标地址相同的数据包
应用层-DNS劫持
DNS劫持,又称为域名劫持
- 攻击者篡改了某个域名的解析结果,使得指向该域名的IP变成了另一个IP
为防止DNS劫持,可以考虑使用更靠谱的DNS服务器,比如:114.114.114.114
- 谷歌:8.8.8.8、8.8.4.4
- 微软:4.2.2.1、4.2.2.2
- 百度:180.76.76.76
- 阿里:223.5.5.5、223.6.6.6
**HTTP劫持:对HTTP数据包进行拦截处理,比如插入JS代码。**比如你访问某些网站时,在右下角多了个莫名其妙的弹窗广告。
HTTP协议的安全问题
HTTP协议默认是采取明文传输的,因此会有很大的安全隐患 常见的提高安全性的方法是:对通信内容进行加密后,再进行传输 常见的加密方式有
- 不可逆
可逆
- 对称加密:DES、3DES、AES等
- 非对称加密:RSA等
- 其它
混合密码系统
- 数字签名
- 证书
常见名词
- encrypt:加密
- decrypt:解密
- plaintext:明文
- ciphertext:密文
假设人物
为了便于学习,设计 个虚拟人物 Alice,Bob: 互相通信 Eve:窃听者 Mallory:主动攻击者
如何防止被监听
对数据进行加密
如何加密解密?
使用对称加密
注意:互联网没办法安全的秘钥
秘钥配送问题
在使用对称加密时,一定会遇到密钥配送问题
如果Alice将使用对称加密过的消息发给了Bob
只有将密钥发送给Bob,Bob才能完成解密
可能会被Eve窃取密钥
最后Eve也能完成解密
如何解决秘钥配送问题
有以下几种解决密钥配送的方法
- 事先共享密钥(比如私下共享)
- Diffie-Hellman密钥交换
- 非对称加密
混合系统(Hybrid Cryptosystem)
对称加密的缺点 不能很好地解决密钥配送问题(密钥会被窃听) 非对称加密的缺点 加密解密速度比较慢 混合密码系统:是将对称加密和非对称加密的优势相结合的方法 解决了非对称加密速度慢的问题 并通过非对称加密解决了对称加密的密钥配送问题 网络上的密码通信所用的SSL/TLS都运用了混合密码系统
混合密码加密
会话密钥(session key )
为本次通信随机生成的临时密钥
作为对称加密的密钥,用于加密消息,提高速度
加密步骤(发送消息)
发送出去的内容包括
混合密码解密
**解密步骤(收到消息) **
① 消息接收者用自己的私钥解密出会话密钥
② 再用第①步解密出来的会话密钥,解密消息
混合加密的流程
Alice >>> Bob 发送过程(加密过程) 接收过程(解密过程)
如何防止被篡改
Alice发的内容有可能是被篡改的,或者有人伪装成Alice发消息,或者就是Alice发的,但她可以否认
问题来了: Bob如何确定这段消息的真实性?如何识别篡改、伪装、否认?
使用数字签名
如何验证公钥的合法性
如果遭遇了中间人攻击,那么 公钥将可能是伪造的
数字签名
特点:
在数字签名技术中,有以下2种行为 生成签名 由消息的发送者完成,通过“签名密钥”生成
验证签名 由消息的接收者完成,通过“验证密钥”验证
作用
如果有人篡改了消息内容或签名内容,会是什么结果? 签名验证失败,证明内容被篡改了
数字签名不能保证机密性? 数字签名的作用不是为了保证机密性,仅仅是为了能够识别内容有没有被篡改
数字签名的作用 确认消息的完整性 识别消息是否被篡改 防止消息发送人否认
let { generateKeyPairSync, createSign, createVerify } = require('crypto');
let passphrase = 'zhufeng';
let rsa = generateKeyPairSync('rsa', {
modulusLength: 1024,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase
}
});
let content = 'hello';
const sign = getSign(content, rsa.privateKey, passphrase);
let serverCertIsValid = verifySign(content, sign, rsa.publicKey);
console.log('serverCertIsValid', serverCertIsValid);
function getSign(content, privateKey, passphrase) {
var sign = createSign('RSA-SHA256');
sign.update(content);
return sign.sign({ key: privateKey, format: 'pem', passphrase }, 'hex');
}
function verifySign(content, sign, publicKey) {
var verify = createVerify('RSA-SHA256');
verify.update(content);
return verify.verify(publicKey, sign, 'hex');
}
总结
既然是加密,那肯定是不希望别人知道我的消息,所以只有我才能解密
公钥负责加密,私钥负责解密
既然是签名,那肯定是不希望有人冒充我发消息,所以只有我才能签名
私钥负责签名,公钥负责验签
证书
说到证书首先联想到的是驾驶证、毕业证、英语四六级证等等,都是由权威机构认证的 密码学中的证书,全称叫公钥证书(Public-key Certificate,PKC),跟驾驶证类似
- 里面有姓名、邮箱等个人信息,以及此人的公钥
- 并由认证机构(Certificate Authority,CA)施加数字签名
CA就是能够认定“公钥确实属于此人”并能够生成数字签名的个人或者组织
- 有国际性组织、政府设立的组织
- 有通过提供认证服务来盈利的企业
- 个人也可以成立认证机构
证书的使用
各大CA的公钥,默认已经内置在浏览器和操作系统中
注册和下载
非对称加密
在非对称加密中,密钥分为加密密钥、解密密钥2种,它们并不是同一个密钥 加密密钥:一般是公开的,因此该密钥称为公钥(public key) 因此,非对称加密也被称为公钥密码(Public-key Cryptography) 解密密钥:由消息接收者自己保管的,不能公开,因此也称为私钥(private key)
特点:
公钥和私钥是一一对应的,不能单独生成,一对公钥和私钥统称为密钥对(key pair)
由私钥加密的密文,必须使用与该私钥对应的公钥才能解密
目前使用最广泛的非对称加密算法是 RSA RSA的名字,由它的3位开发者,即Ron Rivest、Adi Shamir 、Leonard Adleman 的姓氏首字母
RSA加密算法
let { generateKeyPairSync, privateEncrypt, publicDecrypt } = require('crypto');
let rsa = generateKeyPairSync('rsa', {
modulusLength: 1024,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: 'server_passphrase'
}
});
let message = 'hello';
let enc_by_prv = privateEncrypt({
key: rsa.privateKey, passphrase: 'server_passphrase'
}, Buffer.from(message, 'utf8'));
console.log('encrypted by private key: ' + enc_by_prv.toString('hex'));
let dec_by_pub = publicDecrypt(rsa.publicKey, enc_by_prv);
console.log('decrypted by public key: ' + dec_by_pub.toString('utf8'));
原理:
let p = 3, q = 11;//计算完立刻销毁
let N = p * q;
let fN = (p - 1) * (q - 1);//欧拉函数
let e = 7;
for (var d = 1; e * d % fN !== 1; d++) {//拓展欧几里得算法
d++;
}
//d=3
let publicKey = { e, N };
let privateKey = { d, N };
function encrypt(data) {
return Math.pow(data, publicKey.e) % publicKey.N;
}
function decrypt(data) {
return Math.pow(data, privateKey.d) % privateKey.N;
}
let data = 5;
let secret = encrypt(data);
console.log(secret);//14
let _data = decrypt(secret);
console.log(_data);//5
// 1024位二进制数分解
/**
公开 N e c
私密 d
e * d % fN == 1
(p - 1) * (q - 1)
N = p * q
*/
ECC原理
椭圆曲线加密算法(ECC) 是基于椭圆曲线数学的一种公钥加密的算法
使用:
let { createECDH } = require('crypto');
const clientDH = createECDH('secp521r1');
const clientDHParams = clientDH.generateKeys();
const serverDH = createECDH('secp521r1');
const serverDHParams = serverDH.generateKeys();
const clientKey = clientDH.computeSecret(serverDHParams);
const serverKey = serverDH.computeSecret(clientDHParams);
console.log('clientKey', clientKey.toString('hex'));
console.log('serverKey', serverKey.toString('hex'));
Diffie-Hellmann密钥交换算法
Diffie-Hellman算法是一种密钥交换协议,它可以让双方在不泄漏密钥的情况下协商出一个密钥来
原理:
let N = 23;
let p = 5;
let secret1 = 6;//这是密钥
let A = Math.pow(p, secret1) % N;//8
console.log('p=', p, 'N=', N, 'A=', A);
let secret2 = 15;
let B = Math.pow(p, secret2) % N;//19
console.log('p=', p, 'N=', N, 'B=', B);
console.log(Math.pow(B, secret1) % N);
console.log(Math.pow(A, secret2) % N);
node中的Hellman 算法
const { createDiffieHellman } = require('crypto');
var client = createDiffieHellman(512);
var client_keys = client.generateKeys();
var prime = client.getPrime();
var generator = client.getGenerator();
var server = createDiffieHellman(prime, generator);
var server_keys = server.generateKeys();
var client_secret = client.computeSecret(server_keys);
var server_secret = server.computeSecret(client_keys);
console.log('client_secret: ' + client_secret.toString('hex'));
console.log('server_secret: ' + server_secret.toString('hex'));
对称加密(Symmetric Cryptography)
在对称加密中,加密、解密时使用的是同一个密钥 常见的对称加密算法有
- DES
- 3DES
- AES
DES
DES是一种将64bit明文加密成64bit密文的对称加密算法,密钥长度是56bit 规格上来说,密钥长度是64bit,但每隔7bit会设置一个用于错误检查的bit,因此密钥长度实质上是56bit 由于DES每次只能加密64bit的数据,遇到比较大的数据,需要对DES加密进行迭代(反复) 目前已经可以在短时间内被破解,所以不建议使用
3DES
#DES,将DES重复3次所得到的一种密码算法,也叫做3重DES
三重DES并不是进行三次DES加密(加密 -> 加密 -> 加密)
目前还被一些银行等机构使用,但处理速度不高,安全性逐渐暴露出问题
AES(Advanced Encryption Standtard)
- 取代DES成为新标准的一种对称加密算法,又称Rihndael加密法
- AES的密钥长度有128 、192 、256bit 三种
- 目前AES,已经逐步取代DES、3DES ,成为首选的对称加密算法
- 一般来说,我们也不应该去使用任何自制的密码算法,而是应该使用。它经过了全世界密码学家所进行的高品质验证工作
const crypto = require('crypto');
function encrypt(data, key, iv) {
let decipher = crypto.createCipheriv('aes-128-cbc', key, iv);
decipher.update(data);
return decipher.final('hex');
}
function decrypt(data, key, iv) {
let decipher = crypto.createDecipheriv('aes-128-cbc', key, iv);
decipher.update(data, 'hex');
return decipher.final('utf8');
}
let key = '1234567890123456';
let iv = '1234567890123456';
let data = "hello";
let encrypted = encrypt(data, key, iv);
console.log("数据加密后:", encrypted);
let decrypted = decrypt(encrypted, key, iv);
console.log("数据解密后:", decrypted);
单向散列函数(One-way hash function)
常用网站
单向散列函数,可以根据根据消息内容计算出散列值、
散列值的长度和消息的长度无关,无论消息是1bit、10M、100G,单向散列函数都会计算出固定长度的散列值
单向散列的特点:
- 根据任意长度的消息,计算出固定长度的散列值
- 计算速度快,能快速计算出散列值
- 消息不同,散列值也不同
- 具备单向性
单向散列的称呼
单向散列函数,也被称为 消息摘要函数( message digest function) 哈希函数( hash function ) 输出的散列值,也被称为 消息摘要( message digest) 指纹( fingerprint )
常见的散列函数
MD4,MD5 产生128bit的散列值, MD就是Message Digest的缩写 SHA-1 产生160bit的散列值
SHA-2 SHA-256,SHA-384,SHA-512散列值长度分别是 256bit,384bit,512bit
SHA-3 全新标准
如何防止数据被篡改
const salt = '123456';
const sha256 = str => crypto.createHmac('sha256', salt)
.update(str, 'utf8')
.digest('hex')
let ret = sha256(content);
console.log(ret);//64位十六进制 = 256位二进制
HTTPS协议
HTTPS(HyperText Transfer Protocol Secure),译为:超文本传输安全协议 常称为HTTP over TLS、HTTP over SSL、HTTP Secure HTTPS的默认端口号是443(HTTP是80)
SSL/TLS
HTTPS是在HTTP的基础上使用SSL/TLS来加密报文,对窃听和中间人攻击提供合理的防护 SSL/TLS也可以用在其他协议上,比如:
- FTP → FTPS
- SMTP → SMTPS
SSL/TLS历史
历史版本信息 SSL 1.0:因存在严重的安全漏洞,从未公开过 SSL 2.0:1995年,已于2011年弃用(RFC 6176) SSL 3.0:1996年,已于2015年弃用(RFC 7568) TLS 1.0:1999年(RFC 2246) TLS 1.1:2006年(RFC 4346) TLS 1.2:2008年(RFC 5246) TLS 1.3:2018年(RFC 8446) 有没有发现:TLS的RFC文档编号都是以46结尾
SSL 发展到 v3 时已经证明了它自身是一个非常好的安全通信协议,于是互联网工程组 IETF 在 1999 年把它改名为 TLS(传输层安全,Transport Layer Security),正式标准化,版本号从 1.0 重新算起,所以 TLS1.0 实际上就是 SSLv3.1。
SSL/TLS工作在那一层
HTTPS的成本
证书的费用
- 加解密计算
- 降低了访问速度
有些企业的做法是:包含敏感数据的请求才使用HTTPS,其他保持使用HTTP www.icbc.com.cn/ mybank.icbc.com.cn/
TLS1.2的连接过程
① Client Hello TLS的版本号 支持的加密组件(Cipher Suite)列表 加密组件是指所使用的加密算法及密钥长度等
② Server Hello TLS的版本号 一个随机数(Server Random)
③ Certificate 服务器的公钥证书(被CA签名过的)
④ Server Key Exchange 用以实现ECDHE算法的其中一个参数(Server Params) ECDHE是一种密钥交换算法 为了防止伪造,Server Params经过了服务器私钥签名
⑤ Server Hello Done 告知客户端:协商部分结束
目前为止,客户端和服务器之间通过明文共享了 Client Random、Server Random、Server Params 而且,客户端也已经拿到了服务器的公钥证书,接下来,客户端会验证证书的真实有效性
⑥ Client Key Exchange 用以实现ECDHE算法的另一个参数(Client Params) 目前为止,客户端和服务器都拥有了ECDHE算法需要的2个参数:Server Params、Client Params 客户端、服务器都可以 使用ECDHE算法根据Server Params、Client Params计算出一个新的随机密钥串:Pre-master secret 然后结合Client Random、Server Random、Pre-master secret生成一个主密钥 最后利用主密钥衍生出其他密钥:客户端发送用的会话密钥、服务器发送用的会话密钥等
告知服务器:之后的通信会采用计算出来的会话密钥进行加密
⑧ Finished 包含连接至今全部报文的整体校验值(摘要),加密之后发送给服务器 这次握手协商是否成功,要以服务器是否能够正确解密该报文作为判定标准
⑨ Change Cipher Spec ⑩ Finished 到此为止,客户端服务器都验证加密解密没问题,握手正式结束 后面开始传输加密的HTTP请求和响应
HTTP2
HTTP协议的不足
同一时间,一个连接只能对应一个请求 针对同一个域名,大多数浏览器允许同时最多6个并发连接 只允许客户端主动发起请求 一个请求只能对应一个响应 同一个会话的多次请求中,头信息会被重复传输 通常会给每个传输增加500~800字节的开销 如果使用 Cookie,增加的开销有时会达到上千字节
SPDY
SPDY(speedy的缩写),是基于TCP的应用层协议,它强制要求使用SSL/TLS 2009年11月,Google宣布将SPDY作为提高网络速度的内部项目
SPDY与HTTP的关系 SPDY并不用于取代HTTP,它只是修改了HTTP请求与响应的传输方式 只需增加一个SPDY层,现有的所有服务端应用均不用做任何修改
SPDY是HTTP/2的前身
2015年9月,Google宣布移除对SPDY的支持,拥抱HTTP/2
比较
HTTP/2,于2015年5月以RFC 7540正式发表 根据W3Techs的数据,截至2019年6月,全球有36.5%的网站支持了HTTP/2 HTTP/1.1和HTTP/2速度对比 www.http2demo.io/ http2.akamai.com/demo
HTTP/2在底层传输做了很多的改进和优化,但在语意上完全与HTTP/1.1兼容 比如请求方法(如GET、POST)、Status Code、各种Headers等都没有改变
因此,要想升级到HTTP/2 开发者不需要修改任何代码 只需要升级服务器配置、升级浏览器
http特性
二进制格式
HTTP/2采用二进制格式传输数据,而非HTTP/1.1的文本格式
二进制格式在协议的解析和优化扩展上带来更多的优势和可能
http2的优势
数据流:已建立的连接内的双向字节流,可以承载一条或多条消息 所有通信都在一个TCP连接上完成,此连接可以承载任意数量的双向数据流
- 消息:与逻辑HTTP请求或响应消息对应,由一系列帧组成
- 帧:HTTP/2通信的最小单位,每个帧都包含帧头(会标识出当前帧所属的数据流)
- 来自不同数据流的帧可以交错发送,然后再根据每个帧头的数据流标识符重新组装
多路复用(Multiplexing)
客户端和服务器可以将 HTTP消息分解为互不依赖的帧,然后交错发送,最后再在另一端把它们重新组装起来
并行交错地发送多个请求,请求之间互不影响
并行交错地发送多个响应,响应之间互不干扰
使用一个连接并行发送多个请求和响应
不必再为绕过HTTP/1.1限制而做很多工作
优先级: HTTP/2 标准允许每个数据流都有一个关联的权重和依赖关系 可以向每个数据流分配一个介于1至256之间的整数
每个数据流与其他数据流之间可以存在显式依赖关系
客户端可以构建和传递“优先级树”,表明它倾向于如何接收响应
服务器可以使用此信息通过控制CPU、内存和其他资源的分配设定数据流处理的优先级
在资源数据可用之后,确保将高优先级响应以最优方式传输至客户端
头部压缩 HTTP/2使用HPACK压缩请求头和响应头 可以极大减少头部开销,进而提高性能
- 早期版本的HTTP/2和SPDY使用 zlib压缩
- 可以将所传输头数据的大小减小85%~88%
- 但在2012年夏天,被攻击导致会话劫持
- 后被更安全的HPACK取代
服务器推送
服务器可以对一个客户端请求发送多个响应
除了对最初请求的响应外,服务器还可以向客户端推送额外资源,而无需客户端额外明确地请求
缺点:
队头阻塞问题
握手延迟
HTTP3
Google觉得HTTP/2仍然不够快,于是就有了HTTP/3 HTTP/3由Google开发,弃用TCP协议,改为使用基于UDP协议的QUIC协议实现
QUIC(Quick UDP Internet Connections),译为:快速UDP网络连接,由Google开发,在2013年实现
于2018年从HTTP-over-QUIC改为HTTP/3
疑问
HTTP/3基于UDP,如何保证可靠传输? 由QUIC来保证
为何Google不开发一个新的不同于TCP、UDP的传输层协议? 目前世界上的网络设备基本只认TCP、UDP 如果要修改传输层,意味着操作系统的内核也要修改 另外,由IETF标准化的许多TCP新特性都因缺乏广泛支持而没有得到广泛的部署或使用 因此,要想开发并应用一个新的传输层协议,是极其困难的一件事情
特性:
连接迁移
TCP基于4要素(源IP、源端口、目标IP、目标端口) 切换网络时至少会有一个要素发生变化,导致连接发生变化当连接发生变化时,如果还使用原来的TCP连接,则会导致连接失败,就得等原来的连接超时后重新建立连接 所以我们有时候发现切换到一个新网络时,即使新网络状况良好,但内容还是需要加载很久 如果实现得好,当检测到网络变化时立刻建立新的TCP连接,即使这样,建立新的连接还是需要几百毫秒的时间 QUIC的连接不受4要素的影响,当4要素发生变化时,原连接依然维持 QUIC连接不以4要素作为标识,而是使用一组Connection ID(连接ID)来标识一个连接 即使IP或者端口发生变化,只要Connection ID没有变化,那么连接依然可以维持
比如 当设备连接到Wi-Fi时,将进行中的下载从蜂窝网络连接转移到更快速的Wi-Fi连接 当Wi-Fi连接不再可用时,将连接转移到蜂窝网络连接
问题: 据Google和Facebook称,与基于TLS的HTTP/2相比,它们大规模部署的QUIC需要近2倍的CPU使用量
- Linux内核的UDP部分没有得到像TCP那样的优化,因为传统上没有使用UDP进行如此高速的信息传输
- TCP和TLS有硬件加速,而这对于UDP很罕见,对于QUIC则基本不存在
随着时间的推移,相信这个问题会逐步得到改善
openssl
- linux中的openssl 是SSL/TLS协议和多种加密算法的开源实现
- openssl包括libcrypto实现算法、libssl 实现TLS/SSL协议,libssl是基于会话的,实现了身份认证 ,数据加密, 会话完整性的一个TLS/SSL的库。
查看版本
openssl version -a
摘要算法
openssl dgst -help
- file... files to digest (default is stdin) 生成摘要的文件
- -out outfile Output to filename rather than stdout 输出文件
- -sign val Sign digest using private key 使用私钥签名
- -verify val Verify a signature using public key 使用公钥验证签名
- -signature infile File with signature to verify 验证的签名的文件
- -hex Print as hex dump 以16进制打印
- -hmac val Create hashed MAC with key 创建hashed过的消息摘要
echo 123 > msg.txt
openssl dgst -md5 msg.txt
openssl dgst -sha1 msg.txt
openssl dgst -sha256 msg.txt
对称加密
openssl enc -help
- -in infile Input file 输入要加密的文件
- -out outfile Output file 输出加密后的文件
- -e Encrypt 加密
- -d Decrypt 解密
- -a Base64 encode/decode, depending on encryption flag Base64编码和解码
- -pass val Passphrase source 指定密码
- -k val Passphrase 指定密码
openssl enc -e -aes128 -a -k 123456789 -in msg.txt -out enc_msg.txt
openssl enc -d -aes128 -a -k 123456789 -in enc_msg.txt -out dec_msg.txt
openssl enc -e -aes128 -a -pass pass:123456 -in msg.txt -out enc_msg.txt -P
openssl enc -d -aes128 -a -pass pass:123456 -in enc_msg.txt -out dec_msg.txt
RSA非对称加密
openssl genrsa -help
- -aes256 是使用aes256算法加密这个私钥
- -passout 指定加密的密钥
- -out output the key to file 指明输出文件
- -in 指定输入文件
- -pubout 输出公钥信息; 根据私钥的信息得出公钥
//生成加密的私钥
openssl genrsa -aes256 -passout pass:123456 -out private.key 2048
//生成不加密的私钥
openssl genrsa -out private.key 1024
//生成公钥
openssl rsa -pubout -in private.key -out public.key
RSA加解密
openssl rsautl -help
- -in infile Input file 输入文件(待加密或待解密的文件)
- -out outfile Output file 输出文件 加密解密后的文件
- -inkey val Input key 输入加密的公钥
- -encrypt Encrypt with public key 使用公钥加密
- -decrypt Decrypt with private key 使用私钥解密
- -pubin Input is an RSA public 表明输入的是公钥(默认是私钥)
- -sign Sign with private key 表明使用私钥签名
- -verify Verify with public key 表明使用公钥验证签名
- -hexdump Hex dump output 以十六进制形式输出
//公钥加密
openssl rsautl -encrypt -inkey public.key -pubin -in msg.txt -out enc.msg.txt
//私钥解密
openssl rsautl -decrypt -inkey private.key -in enc.msg.txt -out dec.msg.txt
数字签名
//摘要后使用RSA私钥签名,摘要算法sha256
openssl dgst -sign private.key -sha256 -out sign.msg.txt msg.txt
//使用RSA公钥验证签名
openssl dgst -verify public.key -sha256 -signature sign.msg.txt msg.txt
ECDSA
生成公私钥
//生成ecdsa私钥
openssl ecparam -genkey -name secp256k1 -out ec.private.key
//提取 ecdsa 公钥
openssl ec -in ec.private.key -pubout -out ec.public.key
数字签名
//使用ECDSA私钥进行签名 (sha256)
openssl dgst -sign ec.private.key -sha256 -out sign.msg msg.txt
//使用ECDSA公钥进行签名验证
openssl dgst -verify ec.public.key -sha256 -signature sign.msg msg.txt