本文并不是讲算法的实现原理,主要是常用算法的一些特点进行总结,结合场景来看算法的使用。内容分为:
1 算法对比介绍
2 算法场景应用
3 常见的验证方式
常用算法
消息摘要算法
描述:大家最常用的
MD5
就是摘要算法之一,消息摘要算法的特征是加密过程中不需要使用密钥,经过加密的数据是不可逆的,无法通过结果逆向解出加密内容。如下图
定义
摘要算法:通过输入任意长度内容
柔和而产生固定长度
的伪随机
输出内容的算法,它主要 的作用是用来验证数据的完整性
特点
- 密文固定长度(输出总是固定长度的密文):无论输入的信息有多长,计算出来的消息摘要长度总是固定,加密输出的内容越长约安全
- 密文唯一性(输出内容总是伪随机的):不同内容加密得到的内容总是可以通过随机性验证的,但是相同内容加密结果相同
- 密文单向不可逆性(输出内容不可逆):加密得到的内容不可以反向解密
- 密钥安全性强(不需要考虑密钥的传输,适合分布式网络中使用):由于加密内容的唯一性和不可逆特性,只有在加密过程中使用特殊的字符串将原内容拼接、打散、混淆等操作,这个特殊的字符串可以称之为盐,盐 柔和方式的多种多样,使得非常困难通过碰撞而得到两个完全相同的密文。而盐针对多个客户端是固定的,无法改变的,所以并不存在密钥的管理与分发,适合用在分布式网络中使用。
常见算法
下方列举一些消息摘要算法使用频率比较高的算法,在网上都可以搜索到
- MD(Message Digest):消息摘要,生成的消息摘要为128位,常用算法MD2,MD4,
MD5
- SHA(Secure Hash Algorithm):安全散列,常用SHA-1(160位),
SHA-256
,SHA-512 - MAC(Message Authentication Code):消息认证码 ,MAC算法结合了MD5和SHA算法的优势,并加入密钥的支持,是一种更为安全的消息摘要算法,常用算法HmacMD5、HmacSHA1、HmacSHA256等
对称加密
如下图
定义
对称加密:使用同一密钥加密和解密
数据。
特点
- 单密钥:加密和解密数据的密钥相同
- 加解密速度快:相对速度快,适合对大数据的加解密
- 密钥安全性弱:由于加密方和解密方使用了相同的密钥,因此需要考虑密钥的同步问题。加密方法都是公开的,一旦密钥在传输过程中被截获很容易破解数据,所以密钥的管理,时效性,定期更换至关重要。
常用算法
常用的单向加密算法如下:
DES
(Data Encryption Standard):数据加密标准,速度较快,适用于加密大量数据的场合;AES
(Advanced Encryption Standard):安全级别高,支持128、192、256、512位密钥的加密;- 3DES :基于DES,对一块数据用三个不同的密钥进行三次加密,强度更高;
非对称加密
如下图
定义
非对称加密:是一种密钥的保密方法,加解密数据需要一对密钥
,这对密钥称为公钥和私钥
,如果用公钥加密,只能用私钥解密。因为加解密需要使用两个不同的密钥,所以叫做非对称加密。
特点
- 密钥对:加解和解密数据的密钥不同,加解密的密钥为一对密钥。一般情况公钥用作加密,私钥用作解密。
- 加解密速度慢:由于数据安全性的考虑,必然会牺牲时效性,相比之下加解密速度较慢
- 密钥安全性强:由于加解密使用了公私密钥对,在传输过程中只
需要考虑公钥的交换
,私钥始终保存在本地,而公钥被截获依然无法破解数据,所以安全性非常高。
常用算法
RSA
,背包算法,
Elgamal,Rabin,D-H,ECC
(椭圆曲线加密算法)
场景应用
对于加密算法的应用有如下场景:
身份认证角度
- 身份认证:是指被访问者校验访问者身份的一种认证方式
- 服务端验证客户端的登陆及请求身份
- 客户端验证是否是可信的服务器来源
- 服务端与服务端的接口访问身份认证
数据安全角度
- 数据安全:对数据的安全角度考虑
- 安全传输:保证数据传输过程是密文的,一旦数据被截获也能尽可能保证数据密文不可破解
- 安全存储:保证数据是密文存储在数据库或文件中
- 真实完整性:保证原始数据真实、完整未被篡改
常见验证方式
消息摘要验证
摘要验证是对消息的真实完整性验证的一种应用
工作原理
摘要验证流程
摘要服务说明:摘要服务作用只负责将原始数据通过某种字符串混淆方式,通过消息摘要算法的处理后输出消息摘要
- 消息发送方在发送数据前先通过摘要服务创建消息摘要digestA
- 输入original data至摘要服务
- 摘要服务将数据混淆 消息摘要算法生成摘要返回digestA
- 消息发送方将original data digestA发送
- 消息接收方将original data发送至摘要服务获取digestB
- 消息接受方验证digestA与digestB的一致性
- 接受方返回结果
密码存储/令牌认证
下图举例从用户注册,用户登陆,用户访问消息摘要算法的一些应用
工作原理
用户注册/登陆/访问场景流程
用户注册/登陆/访问场景流程的消息摘要算法的使用说明:
- 用户注册
- 用户提交表单到应用服务器
- 服务器对
密码进行摘要算法加密
- 将用户信息校验唯一性后存入数据库
- 返回用户注册成功
- 用户登陆
- 提交用户名密码到服务器
- 将用户
密码进行摘要算法加密
- 使用加密后的密码 用户查询用户信息
- 查询失败返回登陆失败
- 查询成功后进行身份token生成
- 用户ID 过期时间 随机数
消息摘要处理
base64 - 通过cookie或者header方式返回给客户端
- 登陆成功
- 用户ID 过期时间 随机数
- 用户访问
- 用户发送请求参数 token
- 服务端将token 进行base64解密出原始数据和摘要密文
- 摘要验证:
将原始数据进行摘要加密后的得到的密文与摘要密文进行对比
- 若校验失败返回
- 若校验成功(包括有效期校验),进行逻辑处理
- 返回数据
令牌认证的问题
- 不规范:没有固定的规范,增加了沟通成本
- 令牌安全性问题:明文传输,一旦被截获便可模拟用户所有操作
接下来看JWT如何解决令牌规范性问题
JWT(Json Web Token)
JWT是一种基于token的web身份认证方式,也是上诉token身份认证的升级版,它规定了token的格式及有效载荷
工作原理
主要解决问题:解决跨域身份认证问题,确切的说是同域下的多个子域名单点登陆(sso)问题。
原理
单点登陆工作流程
上图为使用JWT的单点登陆原理图:
- 用户登陆a.oa.com站点
- a站点服务端调用jwt服务生成用户身份token
- JWT服务派发用户token
- a站点服务端将身份token通过cookie方式写入父级域
- 用户在同一客户端访问b.oa.com站点
- 客户端携带用户参数 身份token(cookie或者header方式)
- b站点服务端调用jwt服务验证token有效性
- JWT服务验证token,返回验证结果
- b站点收到验证失败,直接返回客户端验证失败,登陆失效
- b站点收到验证成功,逻辑处理,返回客户端数据
JWT格式
代码语言:javascript复制接下来我们看下JWT服务所生成的token,下面token为了方便查看进行了换行处理
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
eyJpc3MiOiddJfand0XyIsImF1ZCI6IjEwMDAwIiwiaWF
0IjoxNTkzODczODU1LCJleHAiOjE1OTM4ODEwNTUsIm5i
ZiI6MCwic3ViIjoiIiwianRpIjoiYmQ4ZjhiMzg1ZGVmO
GM0N2UzYjE1MzRlYTdmZjhlMzkiLCJsdWQiOiIxMDAwMCJ9.
5p9FqE7AgJg1EQTp167JddEUFHvvOaRztMHPXFBpN917I
JWT的格式为:header.payload.signature
- header:为json对象,描述签名算法及token类型,json对象最终使用base64算法转成字符串
{
"alg": "MD5", // alg 描述签名使用的算法
"typ": "JWT" // typ 描述token的类型
}
- payload:为json对象,是签发人信息、用户信息、过期时间、jwt编号信息的载体,官方标准内容为前七个,也可以自定义,json对象最终使用base64算法转成字符串
{
"iss": "JWT-SERVER01" , //(issuer):签发人信息
"exp": "60" , //(expiration time):过期时间
"sub": "login-token" , //(subject):jwt主题
"aud": "UID-001" , //(audience):受众用户
"nbf": "2020-07-05 23:00:00" , //(Not Before):生效时间
"iat": "2020-07-05 23:00:00" , //(Issued At):签发时间
"jti": "JW-2032" , //(JWT ID):JWT编号
"u_name": "jays" , //(u_name):用户自定义字段
"u_role": "admin" , //(u_role):用户自定义字段
}
- Signature:签名的作用主要是验证数有效性,是使用alg指定的方法将header和payload字符串进行拼接 加盐
消息摘要加密算法
,生成签名,最终将三部分内容用点(.)拼接返回给客户端
JWT注意事项
- base64的可逆性:header与payload内容是可以被客户端base64解密的,所以不要放入关键信息在header和payload
- signature摘要安全性问题:jwt一旦被截获,黑客便可以利用signature模拟用户登陆,所以jwt的过期时间不应该过长,传输过程最好使用https传输
接下来看数字签名如何解决摘要信息的安全传输问题
数字签名(signature)
在上诉的JWT案例中我们应用到了签名技术,使用的加密方法为消息摘要算法的MD5,所以可以简单理解把对一个信息的摘要称为该消息的指纹或签名,它的作用是保证消息源的可信性,消息的真实性和完整性。
工作原理
数字签名应该具有唯一性和不可逆性 ,消息摘要算法是数字签名最广泛的应用,在JWT中提到令牌的安全性,而令牌中的signature一旦被泄露,便可以模拟用户的登陆,所以摘要签名的安全性非常重要,数字签名技术采用消息摘要算法 非对称加密方式实现。
数字签名工作流程
- 创建公私钥:发送方提前创建好公钥publicKey(用作签名解密)和私钥privateKey(用作摘要加密生成签名)
- 发送数据
- 创建摘要:将原始数据生成摘要密文:original data 摘要算法=>digest
- 创建签名:将摘要密文使用私钥非对称方式加密,digest privateKey 加密方法=>digital signature
- 发送公钥:将publicKey公钥发送给接收端
- 发送原始数据和签名:original data digital signature
- 接受方验证
- 生成摘要:original data 摘要算法=>digestA
- 解密签名:digital signature publicKey 解密算法 => digestB
- 摘要校验:digestA === digestB是否一直,不一致校验失败返回,一致逻辑处理返回数据
数字签名注意事项
- 公钥的安全性:数字签名解决了消息摘要的安全传输问题,但非对称加密依赖公钥解密,而公钥依然需要通过网络进行交换,因此公钥的安全传输非常重要
- 伪造服务端:非对称加密算法是公开的,一旦公钥被泄露,黑客就可以利用公钥解密出摘要信息,在利用黑客的私钥进行加密生成数字签名,然后把将公钥替换成黑客的公钥,这样就成功伪造了发送方,让接收者以为发送方就真实的服务端
接下来看如何使用数字证书解决来源可信和公钥的安全性
数字证书
数字证书:是将服务器的信息和公钥发送至权威认证机构,认证机构通过认证后,会为服务器颁发数字证书,所以数字证书中保存着服务器的公钥,和服务器信息
申请数字证书流程
数字证书工作流程
上图为数字证书验证流程,具体描述如下:
- 提交审核资料:服务端提交服务基础信息(用来认证服务真实有效)和服务器的公钥
- CA机构生成证书:
- 服务器信息审核:CA拿到服务器信息后首先审核服务器信息
- 生成消息摘要:将服务器信息和服务器公钥作为原始数据通过消息摘要算法生成摘要密文
- 生成数字签名:将摘要信息通过CA的私钥使用非对称方法加密生成CA数字签名
- 派发服务器证书:将服务器信息、服务器公钥、CA数字签名组合生成CA为服务器签发的证书
- 派发CA证书:CA证书包含了CA的公钥,用于客户端进行解密CA证书
- 客户端请求服务端数据
- 服务端返回请求数据、服务器证书、CA机构的证书
- 客户端验证:
- 客户端从CA机构证书中取出CA公钥
- 使用服务器证书的服务器信息 服务器公钥信息 摘要算法=>摘要A
- 使用CA公钥解密服务器证书中的CA数字签名后生成摘要B
- 验证摘要A与摘要B一致性,如果一致服务器可信
- 验证服务器发送数据
- 将服务器发送的数据 摘要算法=>摘要C
- 使用服务器公钥解密数字签名的到摘要D
- 验证摘要C和摘要D一致性,如果一致数据可信完整
- 客户端验证完毕
问题思考
- 数字证书解决了服务器公钥加密传输的问题,但是
CA证书本身的公钥传输问题如何确保安全
呢?- 客户端操作系统会内置根证书,CA证书本身的认证最终会由客户端可信的内置根证书来验证是否合法
- 应用数字证书技术保证了公钥在传输过程中的安全 非对称加密算法就解决了原始数据的消息摘要不被截获纂改,非对称加密的速度慢,适合数字证书、数字签名小数据的加解密,那么问题来了,我们的
原始数据依然还是明文传输的
,如何解决原始数据明文传输的问题呢?
接下来看https的安全传输如何实现原始数据的安全传输
HTTPS
https在http的基础上引入了安全层SSL/TLS,安全层有两个主要的职责:对发起 HTTP 请求的数据进行加密操作和对接收到 HTTP 的内容进行解密操作
工作原理
SSL/TLS安全成负责传输数据的加密和解密
工作流程说明
HTTPS如何确保数据加密传输的呢?
数字证书使用了非对称加密的方式确保数字签名、服务器公钥的安全,数字签名使用了非对称加密的方式确保了原始数据消息摘要密文的安全,这样就服务端就将公钥安全的公布给客户端,客户端使用服务端的公钥和约定的对称加密方法(适合大数据加密传输)来加密传递原始数据,具体流程如下说明:
- 安全链接建立:交换公钥,交换新随机数
- 客户端发送协商的对称加密方法、密钥生成方法(也可以简化不传,使用协商的对称加密方法,为了容易理解暂时写上)、客户端随机数
- 服务端接收到消息后发送非对称加密方法、服务端随机数、数字证书(内包含了服务端的公钥和证书的数字签名)
- 客户端验证证书,验证通过解除服务端公钥
- 客户端生成新的随机数
- 客户端交换随机数(用服务端公钥 新的随机数 非对称加密方法=>随机数的密文传输)
- 服务端收到密文,用私钥解密出随机数
(以上步骤保证了客户端拥有了服务端的公钥,客户端和服务端拥有了共用的新的随机数,新的随机数以供数据对称加密传输的密钥生成)
- 数据传输:利用新的随机数生成密钥 协商的对称加密方法加密原始数据传输数据
- 客户端加密数据传输(原始数据 sercet 对称加密方法)
- 服务端解密出原始数据(密文 sercet 对称解密方法)
- 服务返回数据依然使用相同的对称加密方式传输
- 客户端解密同理
以上就是JWT、数字签名、数字证书、HTTPS场景中对摘要算法、对称加密、非对称加密的使用的总结,如有讲解不正确欢迎指正,但是还没完,身份认证怎么能少了oauth2.0
问题思考
- https及数字证书出于安全考虑,用复杂的认证流程换取了数据安全,必然在用户体验及数据时效性有所降低,所以数字证书一般不会频繁的更换,有效期设置比较长,而且数字证书一般是提前线下申请不能实时在线申请,由于审核的需要也不可能线上实时申请。那么问题来了,假如我们将提供了能力,授权第三方应用进行功能扩展开发
数字证书是否适用于第三方应用授权场景呢?
(例如微信公众平台授权三方应用开发公众号、小程序,及应用身份认证使用微信登陆、QQ登陆等场景)
答案是否定的,目前大多数开放平台使用了oauth2.0认证方式
OAuth2.0
OAuth 2.0 的标准是提案RFC 6749的实现,该标准定义oauth的核心功能是引入了
授权层
,由授权层统一向第三方应用颁发令牌
工作原理
oauth2.0定义了四种获取令牌的方式:授权码、隐藏式、密码式、客户端凭证
1 授权码(authorization-code)
安全性高,适用于开放平台统一授权第三方应用场景、或者A站点要使用B站点用户等数据时,B站点需要为A站点授权:
工作流程说明:
上图为a站点需要统一服务站点提供登陆用户数据等信息
- a站点备案:a站点要使用b站点的用户数据,需要提前在b站点备案信息,b站点为a生成客户端appid和密钥appsercet
- 客户端访问a站点:
- a站点服务端令牌校验:a站点服务端判断令牌有效性,如果无效登陆过期,拼装链接,返回location:https://b.com/oauth2/authorize?response_type=code&app_id=appid&redirect_uri=https://a.com/login&scope=read
- response_type:为请求类型,code代表请求授权码
- app_id:为a站点备案获得的appid
- redirect_uri:授权后的跳转地址
- scope:授权范围
- 获取授权码:客户端收到链接跳转到b站点授权地址
- b站点等待客户确认授权,一旦确认,生成授权码code
- b站点拼接地址将redirect_uri code 返回给客户端
- 获取b站点的身份认证令牌:客户端收到授权回调跳转地址后,跳转到a站点并携带授权码code发送请求
- a站收到客户端授权码后,利用appsercet加密code和请求参数,向b站点发起获取令牌请求
- b站点收到有效授权码后派发身份令牌access_token
- 根据令牌获取用户信息:
- a站点获取到令牌后保存在本地,以供接口请求使用
- a站点根据access_token令牌向b站点获取用户身份信息
- b站点校验access_token令牌有效返回用户信息
- 生成a站点身份令牌:
- a站点获取用户数据后,根据自身的规则生成a站点的身份认证token
- 返回客户端登陆认证成功,派发身份认证令牌
- a站点服务端令牌校验:a站点服务端判断令牌有效性,如果无效登陆过期,拼装链接,返回location:https://b.com/oauth2/authorize?response_type=code&app_id=appid&redirect_uri=https://a.com/login&scope=read
- 客户端再次访问a站点:
- 使用a站点自身派发的令牌请求数据
- 如果需要使用到b站点用户数据,可以继续使用access_token接口获取数据
- a站点逻辑处理返回数据,请求结束
2 隐藏式(implicit)
适用于纯前端获取授权场景,不需要后端的应用,这种方式允许授权方直接向前端颁发令牌,而省去授权码认证的过程,所以称为授权码隐藏式。常见的gitpages的纯前端项目认证就属于这种场景。请求流程说明如下:
- a站点授权提示:如果a站点需要使用b站点的信息,a站点提供一个跳转提示跳转到b站点授权
- 授权链接如:https://b.com/oauth2/authorize?response_type=token&app_id=appid&redirect_uri=CALLBACK_URL&scope=read
- response_type:值为token,代表直接请求令牌
- 跳转到b网站后,用户登陆确认授权后,跳转回redirect_uir地址,并携带token,https://a.com/#token=ACCESS_TOKEN
- 为了token的安全,不被泄露给服务端,采用锚点(#)方式传递
- 授权链接如:https://b.com/oauth2/authorize?response_type=token&app_id=appid&redirect_uri=CALLBACK_URL&scope=read
注意事项:由于token直接传递给前端使用,非常不安全,所以要保证令牌的有效性非常短,尽量做到会话级别有效
3 密码式(password)
oauth2.0允许直接传递用户名、密码的方式来获取令牌,常被用作服务端之间接口请求调用
- 获取b站点的用户信息:
- a站点需要用户提供b站点的用户名、密码信息,由a站点的服务端与b站点交互https://b.com/oauth2/token?grant_type=password&username=USERNAME&password=PASSWORD&app_id=appid
- grant_type:password代表使用用户名、密码的方式获取
- b站点验证通过通过接口响应返回给a站点服务端token
- a站点需要用户提供b站点的用户名、密码信息,由a站点的服务端与b站点交互https://b.com/oauth2/token?grant_type=password&username=USERNAME&password=PASSWORD&app_id=appid
注意事项:这种方式需要用户将b网站的用户名、密码暴露给a站点,风险非常大,不建议使用
4 客户端凭证(client credentials)
不适用于用户的授权认证,适用于对第三方应用的认证,类似于CA机构给服务器颁发证书
- 获取令牌:a站点在服务器上的操作申请令牌
- 根据提前的备案获得appid,appsercet,拼装链接发送请求,https://b.com/oauth2/token?grant_type=client_credentials&app_id=appid&app_sercet=appsercet
- b站点服务端验证appid,appsercet,通过后颁发令牌
- a站点的服务端就拥有了访问b站点的令牌
- 根据提前的备案获得appid,appsercet,拼装链接发送请求,https://b.com/oauth2/token?grant_type=client_credentials&app_id=appid&app_sercet=appsercet
注意事项:这种方式适用于第三方应用,不适用于用户,多个用户有可能使用同一令牌,就好比多个客户端使用同一个数字证书
完,以上为我在工作中对算法的应用理解与总结。(错误之处,欢迎指正)