做外贸网站违法吗,网站建设服务费的摊销期限,crm客户管理系统界面,工作报告是组织进行沟通的有效渠道目录
一、Base64编码
二、哈希算法
三、对称加密(AES/DES)
四、非对称加密(RSA)
五、加盐
六、Web Cryptography API
七、总结 随着信息和数据安全重要性的日益凸显#xff0c;如何保证信息数据在传输的过程中的安全成为开发者重点关注的内容。前端加密通常是指在浏览…目录
一、Base64编码
二、哈希算法
三、对称加密(AES/DES)
四、非对称加密(RSA)
五、加盐
六、Web Cryptography API
七、总结 随着信息和数据安全重要性的日益凸显如何保证信息数据在传输的过程中的安全成为开发者重点关注的内容。前端加密通常是指在浏览器中对各种传输的数据进行各种加密操作。然而前端加密更多的是用来对传输的数据进行简单的混淆为了确保数据在传输过程中不被轻易的篡改和读取。可供我们选择的加密方式有很多种需要我们在开发过程中根据实际的场景选择适合自己的加密解决方案。那么本文将结合应用场景来介绍一下前端开发中常用的加密方法。
一、Base64编码 严格意义上来说Base64并不是一种加密方式它是一种编码方式。Base64就是一种基于64个可打印字符来表示二进制数据的方法。Base64就是包括小写字母a-z、大写字母A-Z、数字0-9、符号、/一共64个字符的字符集任何符号都可以转换成这个字符集中的字符这个转换过程就叫做base64编码。
Base64编码是从二进制到字符的过程可用于在HTTP环境下传递较长的标识信息。采用Base64编码具有不可读性需要解码后才能阅读。Base64由于以上优点被广泛应用于计算机的各个领域。JavaScript中可以使用内置的btoa函数进行Base64编码。btoa函数可以将二进制数据转换为Base64编码的字符串同样也可使用内置函数atob对编码后的字符串进行解码。
// 编码
const base64Str window.btoa(Hello World!);
console.log(base64Str); // SGVsbG8gV29ybGQh
// 解码
const str window.atob(base64Str);
console.log(str); // Hello World!
当然我们也可以使用base64插件。
pnpm add js-base64
使用方法
import { Base64 } from js-base64;// 编码const encode Base64.encode(Hello World!); console.log(encode);// 解码const decode Base64.decode(encode); console.log(decode);
二、哈希算法 散列算法Hash Algorithm又称哈希算法杂凑算法是一种从任意文件中创造小的数字”指纹“的方法。与指纹一样散列算法就是一种以较短的信息来保证文件唯一性的标志这种标志与文件的每一个字节都相关而且难以找到逆向规律。因此当原有文件发生改变时其标志值也会发生改变从而告诉文件使用者当前的文件已经不是你所需求的文件。
Hash 算法能将将任意长度的二进制明文映射为较短的二进制串的算法并且不同的明文很难映射为相同的 Hash 值。
哈希算法Hash Algorithm是一种将任意长度的消息映射为固定长度的消息摘要Message Digest的算法。哈希算法可以将任意长度的输入数据转换为固定长度的输出通常称为哈希值Hash Value或摘要Digest并且满足以下特性
(1) 确定性对于相同的输入数据哈希算法会生成相同的哈希值。
(2) 不可逆性无法从哈希值中推导出原始的输入数据。
(3) 唯一性不同的输入数据生成的哈希值应尽可能不同。
(4) 散列性即使输入数据仅有微小的变化生成的哈希值应该有很大的差异。
因此哈希算法广泛应用于密码学、数据完整性校验、数字签名、数据分片等领域。
(1) 数字签名将原始数据的哈希值与签名一起存储以验证签名的完整性和正确性。
(2) 密码存储将用户密码的哈希值存储在数据库中以避免直接存储明文密码提高安全性。
(3) 数据完整性校验将原始数据的哈希值与传输过程中的哈希值进行比对以判断数据是否被篡改。
(4) 数据分片将原始数据分成若干个块对每个块分别计算哈希值以便快速检测数据块的正确性。
比较常见的哈希算法有MD5、SHA-1、SHA-256和SHA-512等。
安装crypto-js
pnpm add crypto-js
使用方法
import CryptoJS from crypto-js;// MD5
const hash CryptoJS.MD5(Message);
// SHA-1
const hash CryptoJS.SHA1(Message);
// SHA-256
const hash CryptoJS.SHA256(Message);
// SHA-512
const hash CryptoJS.SHA512(Message);
三、对称加密(AES/DES) DES全称为Data Encryption Standardy即数据加密标准是一种使用密钥加密的算法。
AES全称为Advanced Encryption StandardAES 算法使用分组密码体制将明文按照固定大小进行分组然后对每一分组进行加密。在加密过程中AES 算法采用了多轮加密的方式每一轮加密都包含了四种操作SubBytes、ShiftRows、MixColumns 和 AddRoundKey。通过这些操作AES 算法可以更加安全高效地对数据进行加密。
AES和DES加密算法是一种对称加密方式所谓对称加密就是加密与解密使用的秘钥(一组字符串是一个。加密和解密端必须使用同一个密钥的才可以进行加密和解密。
AES 加密最常用的模式就是 ECB模式和CBC模式当然还有很多其它模式它们都属于AES加密。ECB模式和CBC模式俩者区别就是 ECB 不需要 iv偏移量而CBC需要。
ECB是一种基础的加密方式密文被分割成分组长度相等的块不足补齐然后单独一个个加密一个个输出组成密文。CBC是一种循环模式前一个分组的密文和当前分组的明文异或或操作后再加密这样做的目的是增强破解难度。
参数Mode为DES/AES的工作方式。
参数padding为填充模式,如果加密后密文长度如果达不到指定整数倍(8个字节、16个字节填充对应字符padding的赋值固定为CryptoJS.pad.Pkcs7即可。
import CryptoJS from crypto-js;//秘钥
const secretKey CryptoJS.enc.Utf8.parse(12345678ABCDEFGH); //16位
// iv偏移量
const iv CryptoJS.enc.Utf8.parse(ABCDEFGH12345678);
// 需要加密的参数数据类型为bytes
const secretMessage Hello World!;
// 加密
const encrypt CryptoJS.AES.encrypt(secretMessage, secretKey, {iv: iv,mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7
}).tostring();
console.log(encrypt);//解密
const decrypt CryptoJS.AES.decrypt(encrypt, secretKey, {iv: iv,mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.Pkcs7
}).toString(CryptoJS.enc.Utf8);
console.log(decrypt);
四、非对称加密(RSA) 非对称加密加密和解密的秘钥不是同一个秘钥这里需要两把钥匙一个公钥 一个私钥 公钥发送给客户端。发送端用公钥对数据进行加密再发送给接收端接收端使用私钥来对数据解密。由于私钥只存放在接受端这边所以即使数据被截获了也是无法进行解密的。
公钥与私钥是一对因为加密和解密使用的是两个不同的密钥所以这种算法叫作非对称加密算法。使用时都是使用公匙加密使用私匙解密。公匙可以公开私匙自己保留。这个公钥和私钥其实就是一组数字其二进制位长度可以是1024位或者2048位。长度越长其加密强度越大相对就比较安全。所以目前为止这种加密算法一直被广泛使用。
常见的非对称加密算法有RSADSA等等本文我们就介绍一个RSA加密也是最常见的一种加密方案。
jsencrypt就是一个基于RSA加解密的js库。
npm install jsencrypt
import JSEncrypt from jsencrypt
// RSA加密
// 创建加密对象实例
const encryptor new JSEncrypt();
//之前ssl生成的公钥复制的时候要小心不要有空格
const pubKey -----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC1QQRl0HlrVv6kGqhgonD6A9SU6ZJpnENQ0blT/ue6Ndt97WRfxtSAs0QoquTreaDtfC4RRX4oCU6BTuHLUmeSvxZS9TzbwoYZq7ObbQAZAYSYDgAA5PHf1wNN20dGMFFgVS/y0ZWvv1UNa2laEz0I8Vmr5ZlzIn88GkmSiQIDAQAB-----END PUBLIC KEY-----;
//设置公钥
encryptor.setPublicKey(pubKey);
// 对内容进行加密
const encrypted encryptor.encrypt(要加密的内容) // RSA解密
//创建解密对象实例
const decrypt new JSEncrypt();
//之前ssl生成的秘钥
const priKey -----BEGIN RSA PRIVATE KEY-----MIICXAIBAAKBgQC1QQRl0HlrVv6kGqhgonD6A9SU6ZJpnENQ0blT/ue6Ndt97WRfxtSAs0QoquTreaDtfC4RRX4oCU6BTuHLUmeSvxZS9TzbwoYZq7ObbQAZAYSYDgAA5PHf1wNN20dGMFFgVS/y0ZWvv1UNa2laEz0I8Vmr5ZlzIn88GkmSiQIDAQABAoGBAKYDKP4AFlXkVlMEP5hS8FtuSrUhwgKNJ5xsDnFV8sc3yKlmKp1a6DETc7N66t/Wdb3JVPPSAy7GaYJc7IsBRZgVqhrjiYiTO3ZvJv3nwAT5snCoZrDqlFzNhR8zvUiyAfGD1pExBKLZKNH826dpfoKD2fYlBVOjz6i6dTKBvCJAkEA/GtL6q1JgGhGLOUenFveqOHJKUydBAk/3jLZksQqIaVxoBjRQNOZjeSO9er0fxgI2kh0NnfXEvHv326WxjBwJBALfTRar040v71GJq1m8eFxADIiPDNh5JD2yb71FtYzH9J5/d8SUHI/CUFoROOhxr3DpagmrnTn28H0088vubKe8CQDKMOhOwx/tS5lqvN0YQj7I6JNKEaR0ZzRRuEmv1pIpAW1S5gTScyOJnVn1tXxcZ9xagQwlT2ArfkhiNKxjrf5kCQAwBSDN5r4jnCMxRv/Kv0bUbY5YWVhw/QjixiZTNn81QTk3jWAVr0su4KmTUkg44xEMiCfjI0Ui3Ah3SocUAxECQAmHCjy8WPjhJN8y0MXSX05OyPTtysrdFzm1pwZNm/tWnhW7GvYQpvE/iAcNrNNb5k17fCImJLH5gbdvJJmCWRk-----END RSA PRIVATE KEY----;
//设置秘钥
decrypt.setPrivateKey(priKey);
//解密之前拿公钥加密的内容
const uncrypted decrypt.decrypt(encrypted) RSA加解密可以应用在用户注册或登录的时候用公钥对密码进行加密再去传给后台后台用私钥对加密的内容进行解密然后进行密码校验或者保存到数据库。 五、加盐 加盐是指在密码哈希过程中引入一个随机生成的字符串称为盐salt并将其与密码进行组合后再进行哈希计算。这个盐值会与每个用户的密码单独关联并且将其存储在数据库中。加盐可以增加密码哈希的复杂度提高密码的安全性即使两个用户使用相同的密码由于使用了不同的盐值其哈希结果也会有所区别。这样即使黑客获得了哈希值也很难通过暴力破解找到原始的密码。
盐值其实就是我们添加的一串随机字符串(这个值可以是固定值、随机数、uuid……)相同的字符串每次都会被加密为完全不同的字符串。
使用加盐加密时需要注意以下两点
1短盐值Short Slat
如果盐值太短攻击者可以预先制作针对所有可能的盐值的查询表。例如如果盐值只有三个 ASCII 字符那么只有 95x95x95857,375 种可能性加大了被攻击的可能性。还有不要使用可预测的盐值比如用户名因为针对某系统用户名是唯一的且被经常用于其他服务。
2盐值复用Salt Reuse
在项目开发中有时会遇到将盐值写死在程序里或者只有第一次是随机生成的之后都会被重复使用这种加盐方法是不起作用的。以登录密码为例如果两个用户有相同的密码那么他们就会有相同的哈希值攻击者就可以使用反向查表法对每个哈希值进行字典攻击使得该哈希值更容易被破解。
所以正确的加盐方法如下
1盐值应该使用加密的安全伪随机数生成器 Cryptographically Secure Pseudo-Random Number GeneratorCSPRNG 产生比如 C 语言的 rand() 函数这样生成的随机数高度随机、完全不可预测
2盐值混入目标文本中一起使用标准的加密函数进行加密
3盐值要足够长经验表明盐值至少要跟哈希函数的输出一样长且永不重复
4盐值最好由服务端提供前端取值使用。
我们一起SHA-256为例实现加盐加密。
安装js-sha256
pnpm install js-sha256
使用方法
import { sha256 } from js-sha256;const generateSalt () {const randomBytes new Uint8Array(16);crypto.getRandomValues(randomBytes);return Array.from(randomBytes, (byte) byte.toString(16).padStart(2, 0)).join();
};
// 盐值
const salt generateSalt();
// 假如一个密码
const password admin123456;
// 盐值和密码进行组合
const saltedPassword salt password;
// 哈希计算
const hash sha256(saltedPassword);
console.log(hash);
六、Web Cryptography API Web Cryptography APIWebCrypto API是现代浏览器内置的一个加密标准可以用于更安全的密码学操作。这个API允许我们在Web应用中实现加密、解密、数字签名等安全功能而无需依赖第三方库或插件。
WebCrypto API是W3C的标准它提供了一套低级别的接口用于执行各种密码学操作。这些接口包括
生成和管理密钥如RSA、AES和HMAC等。
加密和解密支持多种对称和非对称加密算法。
摘要和哈希如SHA-1、SHA-256和MD5等。
数字签名和验证用于确保数据的完整性和来源真实性。
随机数生成用于创建安全的随机数。
window.crypto.subtle就是SubtleCrypto接口主流最新浏览器基本都已经支持该接口并且一致除了safari需要注意。
// fix safari crypto namespaceif (window.crypto !window.crypto.subtle window.crypto.webkitSubtle) {window.crypto.subtle window.crypto.webkitSubtle; }/**
* Detect Web Cryptography API
* return {Boolean} true, if success
*/
function isWebCryptoAPISupported() {return crypto in window subtle in window.crypto;
} getRandomValues 同步方法获取随机数因为性能要求这是一个伪随机数生成器(PRNG)。浏览器也通过添加系统级别的种子来提高熵(不确定性的量度)来满足密码学使用要求。
const size 10;
const array new Uint8Array(size);
window.crypto.getRandomValues(array);// print values to console
for (let i0; i!array.length; i) {console.log(array[i]);
} SubtleCrypto接口
encrypt、decrypt(加解密方法)算法支持RSA-OAEP、AES-CTR、AES-CBC、AES-GCM、AES-CFB。
Sign、verify(签名验签发方法)算法支持RSASSA-PKCS1-v1.5、RSA-PSS、ECDSA、AES-CMAC、HMAC。
Digest(摘要方法)算法支持SHA-1、SHA-256、SHA-384、SHA-512。
GenerateKey生成对称/非对称的密钥(CryptoKey对象)。
DeriveKey 和 deriveBits从原密钥或是从伪随机函数生成的密码/口令中生成出一个密钥。
WrapKey 和 unwrapKey用来保护在不安全信道或不可信环境存储的密钥的方法。
ImportKey 和 exportKey导入密钥转换再导出不同格式。
上面的方法都会返回Promise。
以下是使用WebCrypto API实现一个简单的加密代码如下
// 生成公钥和私钥
const keyPair await window.crypto.subtle.generateKey({name: RSA-OAEP, // 使用RSA-OAEP算法modulusLength: 2048, // 密钥长度为2048位publicExponent: new Uint8Array([1, 0, 1]), // 公共指数为65537hash: SHA-256 // 哈希算法为SHA-256},true, // 生成可导出的密钥对[encrypt, decrypt] // 可用于加密和解密操作
);
keyPair.then(function(result) {// 处理生成的密钥对console.log(result.publicKey); // 打印公钥console.log(result.privateKey); // 打印私钥
}).catch(function(error) {// 处理错误console.error(error);
});
// 加密
async function encryptByRSA(message, publicKey) {// 将消息编码为Uint8Array格式const encodedMessage new TextEncoder().encode(message);// 使用Web Crypto API的encrypt()方法对消息进行加密const encrypted await window.crypto.subtle.encrypt({name: RSA-OAEP // 加密算法为RSA-OAEP},publicKey, // 使用传入的公钥进行加密encodedMessage // 要加密的消息);// 将加密后的数据转换为Base64编码的字符串return window.btoa(String.fromCharCode(...new Uint8Array(encrypted)));
}// 解密 使用RSA私钥对密文进行解密
async function decryptByRSA(ciphertext, privateKey) {// 将Base64编码的密文解码为Uint8Array格式const decodedCiphertext Uint8Array.from(atob(ciphertext),c c.charCodeAt(0));// 使用Web Crypto API的decrypt()方法对密文进行解密const decrypted await window.crypto.subtle.decrypt({name: RSA-OAEP // 解密算法为RSA-OAEP},privateKey, // 使用传入的私钥进行解密decodedCiphertext // 要解密的密文);// 将解密后的数据转换为字符串return new TextDecoder().decode(decrypted);
} 七、总结
以上几种加密方法提供了基本的前端加密方法。大部分时候为了确保数据的安全性会将一些敏感数据(如手机号、身份证号、银行卡号等)发送到服务端然后再服务端进行加密。前端加密并不能确保数据的安全性因为客户端是暴露给用户的任何混淆或加密措施都可能被绕过前端加密防君子不放小人。正确的做法是在保证数据传输过程中通过HTTPS等协议加密并在服务端进行必要的安全校验和加密处理。