加密技术
现代密码学设计原则
柯克霍夫原则: 数据的安全基于密钥而不是算法的保密。即系统的安全取决于密钥,对密钥保密,对算法公开
常用加密码算法
对称加密
- 指加密和解密使用相同密钥的加密算法。对称加密算法的原理很容易理解,通信一方用KEK加密明文,另一方收到之后用同样的KEY来解密就可以得到明文。
-
常见的对称加密算法有DES、3DES、Blowfish、IDEA、RC4、RC5、RC6和AES
-
优点: 对称加密算法的优点是算法公开、计算量小、加密速度快、加密效率高。
-
缺点: 没有非对称加密安全.
-
用途: 一般用于保存用户手机号、身份证等敏感但能解密的信息。
-
示例-crypto.js库
安装方式一: npm install crypto-js
安装方式二: 引用文件
/*
* 加密
* message: 明文
* key: 秘钥
*/
function encryptText(message, key) {
return CryptoJS.AES.encrypt(message, key).toString() // 加密码
}
/**
* 解密
* cipherText: 密文
* key: 秘钥
*/
function decryptText(cipherText, key) {
var bytes = CryptoJS.AES.decrypt(cipherText, key)
var originalText = bytes.toString(CryptoJS.enc.Utf8)
return originalText
}
/**
* 测试对称加密
*/
function testEncrypt() {
let msg = '2022年10月1 国庆放假'
let key = 'h52208_key'
let cipherText = encryptText(msg, key)
// U2FsdGVkX1/3hYWvhOn5aGQlde/4w/hxLqoE2o3DLnmkYzobaaL74GSEEYrvANC2
console.log(cipherText)
let text = decryptText(cipherText, 'h52208_key')
console.log(text)
}
非对称加密
非对称加密算法,使用两把完全不同但又是完全匹配的一对Key:公钥和私钥。
在使用非对称加密算法加密文件时,只有使用匹配的一对公钥和私钥,才能完成对明文的加密和解密过程。
- 优点: 非对称加密与对称加密相比,其安全性更好;
- 缺点: 非对称加密的缺点是加密和解密花费时间长、速度慢,只适合对少量数据进行加密。
- 用途: 一般用于签名和认证。私钥服务器保存, 用来加密, 公钥客户拿着用于对于令牌或者签名的解密或者校验使用.
- 常见的非对称加密算法有: RSA、DSA(数字签名用)、ECC(移动设备用)、RS256 (采用SHA-256 的 RSA 签名)
- 规则:公钥加密,私钥解密
- RSA加密
-
RSA秘钥生成方式
Mac系统内置OpenSSL(开源加密库),所以可以直接在终端上使用命令。
Windows系统可以使用git命令行工具,单击鼠标右键——git bash here调出git bash,生成私钥,密钥长度为1024bit
从私钥中提取公钥
命令行查看
RSA在线生成:toolsjb51.net/password/rs… -
rsa加解密库jsencrypt
-
引入<script src="../lib/js/JSEncrypt.js"></script>
npm install jsencrypt
```
/**
* 加密
*/
function encryptMsg(message){
let publicKey = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdjI9iz4LVwswO5n7xiXv8Zl1Z
HGifqjH7nHN7OCxAMEipxLov2FFCepl4wJPaodqZkUX64kfc2fAM2Zyo6x1v08DR
ln+74iw/7F9ZiQ4eO581iMHA6WCNtLs1K5RkqozSqOiwo6J/C8iZNnE63foIIk+D
f9kovGgOF5k/7DvSiwIDAQAB
-----END PUBLIC KEY-----`
let jsEncrypt = new JSEncrypt()
jsEncrypt.setPublicKey(publicKey) //设置公钥
let encryMessage = jsEncrypt.encrypt(message) //加密message
return encryMessage
}
/**
* 解密
*/
function decodeMsg(encryMsg){
let privateKey = `-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDdjI9iz4LVwswO5n7xiXv8Zl1ZHGifqjH7nHN7OCxAMEipxLov
2FFCepl4wJPaodqZkUX64kfc2fAM2Zyo6x1v08DRln+74iw/7F9ZiQ4eO581iMHA
AoGAMbbCzhdmcnUduRI71hNVwRNvSvm2+G0GfkFjIHlAZL7w7zd32BigU1yTZ6c/
BkZfeSpCG8P/AC3fUeLa5oSru+s7rWE/4i55C7QDRMQqrxZT2SSiyZxw37dKaFld
sASFmd7eDbWNcFedjQ9Z77P5khPzRsPbDaTzl2CW52jDqOECQQD4lfvzkd/ZtRn6
5dYCLjAoQVkFE4CUXyCf5S25hqlnFXylEuBQ2Vr8XR3FtGr1uVrEoa7APxtoJb5g
ij8C5ZB5AkEA5Cgknf+FXttPWwTeF6XnuLmcKp+OBPSuSdLMKIWusQDIGRL5lj0U
PEyWwUimBoUoqCBT10eVE1dMrtZS1rEiIwJATwsqBUYiPtCmRTBl/2V+bJ5y1vlf
jk49SnqOMosOPLgJXVgGOc8TbmGRgPcgd6gLo7Chp4GpjlFKGtp6tMoYSQJBAKa2
CmOEhOCV4TtBqEKhUFszDMA8S9qlKwD4TYNCgy4EwzFHIyY7RSD2WaWrvty+ycFn
tbt1K6GxRW/vXSJQ1f8CQQDaSBq7LvSPrcI8FqyEe/Js0Mfascojuh+VIuA1J2de
K4tFxK7Zri3p/I9ZNUcrbFLJeZuauTWFdG18ZN7NH7M0
-----END RSA PRIVATE KEY-----`
let jsEncrypt = new JSEncrypt()
jsEncrypt.setPrivateKey(privateKey)
let message = jsEncrypt.decrypt(encryMsg) //解密
return message
}
```
不可逆加密算法
Hash算法特别的地方在于它是一种单向算法,一旦加密就不能反向解密得到密码原文。常用在不可还原的密码存储、信息完整性校验等。
- 常见的不可逆加密算法有: MD5、SHA、HMAC
- SHA
js-sha256库
npm i js-sha256
<script src="../ib/js/sha256,js"></script> //引入sha.js文件
<script>
var encodeText = sha256('明天放假');
console.log('encodeText >>> ', encodeText);
//9ed6896513a64af764aef508a53d66C3a2fab162f6b1cd2e31e823a8524741b9
</script>
base64
Base64并不是一种加密方式,明文使用Base64编码后的字符串通过索引表可以直接还原为明文。因此,Base64只能作为一种数据的存储格式
- base64实现
- 安装npm install js _base64
- let Base64 = require(js-base64).Base64//还是rquire
- this.pw = Base64.encode(this.passWord)//还是那些操作
- 在线编码工具:www.jsons.cn/img2base64/
token认证
Token身份验证
流程:
- 客户端使用用户名跟密码请求登录
- 服务端收到请求,去验证用户名与密码
- 验证成功后,服务端会签发一个Token, 再把这个Token发送给客户端
- 客户端收到Token以后可以把它存储起来,比如放在Cookie里或者LocalStorage里
- 客户端每次向服务端请求资源的时候需要带着服务端签发的Token
- 服务端收到请求,然后去验证客户端请求里面带着的Token,如果验证成功,就向客户端返回请求的数据
JWT技术
JWT,全称是Json Web Token, 是JSON风格轻量级的授权和身份认证规范,可实现无状态、分布式的Web应用授权
- jWT的原理:
服务器认证以后,生成一个JSON对象,发回给用户,用户再发回这个JSON对象,客户端收到服务器返回的JWT ,可以储存在Cookie里面,也可以储存在localStorage。此后,客户端每次与服务器通信,都要带上这个JWT。可以把它放在Cookie里面自动发送,但是这样不能跨域,所以更好的做法是放在HTTP请求的头信息Authorization字段里面。
- JWT实现
-
安装npm i jsonwebtoken
-
封装生成和认证token代码
const jwt = require('jsonwebtoken');
const Token = {
encrypt:function(data) { //data加密数据,token-secret, 秘钥,time过期时间1天
return jwt.sign(data, 'token-secret',{expiresIn:1000*60*60*24})
},
decrypt:function(token) {
try {
let data = jwt.verify(token, 'token-secret');
return
token:true,
id:data.id
};
} catch (e) {
return {
token:false,
data:e
}
}
module exports = Token;
- 拦截所有请求进行认证
//捕获所有请求,统一认证
app.all('/*', (req, res, next) => {
// 过滤不需要认证的接口
let arr = ['/api/users/register', '/api/users/login', '/api/users/logout']
if (arr.indexOf(req.url) !== -1) {
next() //放行
return
}
// 客户端将token置入authorization头部,请求接口时发送给服务端
let TokenData = JwtToken.decrypt(req.headers.authorization) //认证token
if (!TokenData.token) {
res.send({
resultCode: -1,
resultInfo: 'token无效',
})
} else {
next()
}
})
- 前端认证接口设置头
funcation loadUserList(pageNo) {
let user = localStorage.getItem('USER')
user = JSON.parse(user)
// axios.defaults.headers.common['Authorization'] = user.token;
axios({
method: 'get',
url: 'http://localhost:3000/api/vistor/list',
//axios库get请求:parmas传参
//axios库post请求: data传参
headers:{
authorization:user.token, //设置token认证头authorization
},
params:{
pageNo
}
}).then(response => {
let data = response.data
if (data.resultCode == 1) {
let result = data.resultInfo //用户列表数据
showUserList(result)
}else{
alert(data.resultInfo)
}
})
}
axios简单封装与拦截器使用request.js
/**
* 封装axios实例
* 1.引入axios库
* axios() 默认axios实例,没有拦截器
* 2.自己封装axios, 定义拦截器
*/
const myAxios = axios.create({
baseURL: 'http://10.7.162.73:3000',
timeout: 2000, //设置请求超时时间
})
// 定义拦截器
myAxios.interceptors.request.use(
config => {
// 设置token到authorization头部
let token = Cookies.get('TOKEN')
if (token) {
config.headers.common['authorization'] = token
}
return config
},
error => {
// 对请求错误做些什么
return Promise.reject(error)
}
)