前端如何安全存储密钥,防止信息泄露
场景
把公钥硬编码在前端代码文件里,被公司安全检测到了要整改,于是整理几种常见的前端密钥存储方案。
1. 设置环境变量再读取
在打包或部署前端应用时,可以将密钥配置为环境变量,在应用运行时通过环境变量读取密钥。这样可以将密钥从源代码中分离出来,避免意外泄露。
a. 前端设置环境变量
将密钥作为前端应用的环境变量进行配置。但是直接使用环境变量存储密钥也是很危险的,前端代码可以被任何人查看和修改,这意味着敏感信息可能会被泄露。
步骤:
-
在 .env 文件中设置环境变量
首先,在项目根目录下的 .env 文件中设置环境变量.
当然,你也可以设置在特定环境的 .env 文件,如 .env.production、.env.test等,这样可以根据不同的环境设置不同的变量值。
VITE_API_KEY = 'your_api_key_here'
-
在 Vue 组件中读取环境变量
console.log(import.meta.env.VITE_API_KEY) // 打印 API 密钥
但是使用这种方法打包后,秘钥仍能在源码中找到。
b. 后端设置环境变量
将密钥存储在后端环境变量中再由前端读取可以提高安全性,这样密钥不会在客户端暴露。
-
后端密钥生成与存储:在后端应用中,生成和存储密钥。可以使用安全的密钥生成算法来生成密钥,并将其存储在后端的安全存储中,如数据库或密钥管理服务。
-
创建API接口:创建一个受保护的API接口来向前端提供密钥。为了提高安全性,可设置此接口需要身份验证,以确保只有经过授权的用户或应用程序可以访问后端的密钥服务。
-
前端请求密钥:前端通过已认证的请求来获取密钥。
对于包含敏感信息的环境变量,应该避免将其暴露给前端。如果确实需要在前端使用某些敏感信息,考虑使用更安全的机制,比如客户端证书或令牌。
2. 配置文件存储
将密钥存储在前端应用的配置文件中。在构建和部署应用时,可以将密钥配置为独立的配置文件,并在应用启动时读取配置文件中的密钥。
但是,在前端应用中使用配置文件来存储密钥也不是一个好的做法,因为前端代码(包括配置文件)最终会被发送到用户的浏览器,这意味着任何有意图的攻击者都可以查看、修改甚至篡改这些配置。
3. 使用加密库加密存储
将密钥进行加密,并将加密后的密钥存储在前端应用中,应用在运行时解密密钥并使用。
这种方法可以提供更高的安全性,防止明文密钥泄露。
常见的做法是使用对称加密算法,将密钥与应用内部的固定值进行加密存储,并在需要使用时进行解密。
-
选择加密算法:选择一个适合的对称加密算法,例如 AES(高级加密标准)。AES 是一种常用的对称加密算法,提供了高强度的加密和解密功能。
-
生成加密密钥:使用选择的算法生成加密密钥。
-
加密密钥:将生成的加密密钥与应用内部的某固定值进行加密,固定值可以是应用的特定字符串或其他数据。将加密后的密钥存储在前端应用中。
-
解密密钥:在需要使用密钥的时候,通过解密算法对加密的密钥进行解密,获取原始的密钥值。解密过程需要使用相同的密钥和算法进行解密操作。
以下是一个示例,展示如何使用 JavaScript 中的 CryptoJS 库进行加密和解密:
// 导入 CryptoJS 库
const CryptoJS = require('crypto-js');// 固定值,用于加密密钥
const fixedValue = 'your_fixed_value';// 原始密钥
const originalKey = 'your_secret_key_value';// 加密密钥
const encryptedKey = CryptoJS.AES.encrypt(originalKey, fixedValue).toString();// 解密密钥
const decryptedKey = CryptoJS.AES.decrypt(encryptedKey, fixedValue).toString(CryptoJS.enc.Utf8);console.log(decryptedKey); // 输出原始密钥
加密存储并不是绝对安全的,它只是增加了密钥泄露的难度。对于高安全性要求的应用,建议将敏感操作放在服务器端进行,避免将加密密钥暴露给前端应用的客户端。
4. 混淆技术
混淆是防止JavaScript代码被轻易阅读和理解的有效方法,它通过一系列自动化的工具转换代码结构,但不改变其功能。混淆虽然提高了代码的保密性,但依然不能防止专业人员通过耐心分析来理解代码。因此,它更多是增加攻击者的分析成本,而不是绝对的保护措施。
关于混淆,详细请看这篇:前端JavaScript代码混淆加密原理
5. 安全存储服务
将密钥存储在专门的密钥管理服务中,如密钥管理系统(Key Management System,KMS)。前端应用在运行时通过安全的协议和认证机制与密钥管理服务通信,获取需要的密钥。这样可以将密钥的管理和保护责任交给专门的服务,提供更高级别的安全性。
这也是一种将敏感数据安全地存储在后端服务器上的方法,以确保数据的保密性和完整性。
实际应用
综合来看,相对比较安全的是方法1b和5。
由于只是为了解决公司安全检测,故只选择了1a+3来存储密钥,其他方法可以考虑作为后续优化方向。
其中CryptoJs库的使用:前端加密JS库--CryptoJS 使用指南
// ------------env.d.ts------------
declare const _MY_GLOBAL_KEY_: string// ------------vite.config.ts------------
// base64加密后的密钥(注意,此处存储的密钥已经使用base64加密过了)
const PRIVATE_KEY = "'xxxxxxxxxxxx'"
export default defineConfig(({ command, mode }) => {return {// ......// 定义全局常量,用于环境变量注入或其他编译时替换define: {_MY_GLOBAL_KEY_: PRIVATE_KEY}}
})// ------------crypto.js------------
import CryptoJS from 'crypto-js'
import JSEncrypt from 'jsencrypt'
const decryptKEY = CryptoJS.enc.Base64.parse(_MY_GLOBAL_KEY_).toString(CryptoJS.enc.Utf8) // Base64解密// rsa解密
export function rsaDecrypt(decryStr) {const decryptor = new JSEncrypt()decryptor.setPrivateKey(decryptKEY)const decrypted = decryptor.decrypt(decryStr)return decrypted
}// 发送请求获取token
getTokenApi().then(res => {const { resultData } = reslet decryptData = nulltry {decryptData = JSON.parse(CryptoJS.enc.Base64.parse(resultData).toString(CryptoJS.enc.Utf8))} catch (error) {console.log('error: ', error)}s3Data.value = decryptDatas3Data.value.ak = rsaDecrypt(decryptData.ak) //RSA解密s3Data.value.sk = rsaDecrypt(decryptData.sk) //RSA解密formData.bucketName = s3Data.value.bucketNames3.value = new window.AWS.S3({accessKeyId: s3Data.value.ak,secretAccessKey: s3Data.value.sk,endpoint: s3Data.value.endpoint,sessionToken: s3Data.value.token})}).catch(err => {proxy.$errorHandle(err)})
拓展
Base64
经常在提到加密算法时看到Base64的使用,Base64的输入是二进制数据,输出是字符串,它是一种将二进制数据转换为字符的方法。通过Base64编码出的字符串只包含ASCII基础字符,如小写字母a-z、大写字母A-Z、数字0-9、符号"+"、"/"。
例如:字符串ShuSheng007
对应的Base64为U2h1U2hlbmcwMDc=
。其中=
比较特殊,是填充符。
要注意的是,Base64不是加密算法,仅仅是一种编码方式,其算法也是公开的,所以并不能依赖它进行加密。
-
为什么要在加密算法中使用Base64
既然Base64不是加密算法,为什么加密算法又要使用它呢。
我们知道加密是将明文、可读的数据转换为加密的、无法阅读的乱码。然而,加密的输出是包含不可打印字符的二进制数据。为了安全传输或存储这些加密数据,需要把他们编码为能够正常处理的 ASCII 字符串。这就是 Base64 编码在加密算法中的作用。
此外,Base64编码是很适合在HTTP环境下使用的,因为HTTP是以传输文本为主的协议,而Base64算法正好可以把传输内容变成文本。
而且由于base64的特性,其大小增加很有限,编码后,不会明显扩大原有文件的大小。
AES加密算法
高级加密标准(AES,Advanced Encryption Standard)是最常见的对称加密算法。
对称加密算法就是加密和解密用相同的密钥,具体的加密流程如下图:
明文P
指没有经过加密的数据。
密钥K
用来加密明文的密码,在对称加密算法中,加密与解密的密钥是相同的。
密钥为接收方与发送方协商产生的,但不可以直接在网络上传输,否则会导致密钥泄漏。通常是通过非对称加密算法加密密钥,然后再通过网络传输给对方,对方再解密。
AES加密函数
把明文P和密钥K作为加密函数的参数输入,则加密函数会输出密文C。
密文C
经加密函数处理后的数据。
AES解密函数
把密文C和密钥K作为解密函数的参数输入,则解密函数会输出明文P。
-
对称加密与非对称加密的区别
对称加密算法
对称加密算法的加密和解密用的密钥是相同的。这种加密方式加密速度非常快,适合经常发送数据的场合。缺点是使用的密钥,它本身的传输比较麻烦,一般用非对称加密来传输。
非对称加密算法
非对称加密算法的加密和解密用的密钥是不同的。通常加密解密的速度比较慢,适合偶尔发送数据的场合。可以用非对称加密算法来串数对称加密算法使用的密钥。常见的非对称加密算法为RSA、ECC和EIGamal。
相关文章:

前端如何安全存储密钥,防止信息泄露
场景 把公钥硬编码在前端代码文件里,被公司安全检测到了要整改,于是整理几种常见的前端密钥存储方案。 1. 设置环境变量再读取 在打包或部署前端应用时,可以将密钥配置为环境变量,在应用运行时通过环境变量读取密钥。这样可以将密…...

银行电子户分账解决电商行业哪些问题
随着电子商务的快速发展,电商银行电子户分账作为金融科技领域的重要一环,逐渐成为现代金融业务的核心。本文将详细探讨电商银行电子户分账的原理、操作流程、安全措施以及在电子商务中的重要作用。 二、电商银行电子户分账的基本概念 电商银行电子户分…...

Web音乐库:SpringBoot实现的音乐网站
2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统,它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等,非常…...

Rust: 加密算法库 ring 如何用于 RSA 数字签名?
本来用 rsa 库基本搞定,但文心一言建议改用 ring 库。原因是 rsa 库已经放弃维护,而 ring 库性能公认很好。但是如何进行 RSA 数字签名,网上几乎查不到这方面材料。仔细查看了 ring 库的源代码和代码注释,终于完成趟坑。总结一下供…...

Matplotlib 网格线
Matplotlib 网格线 Matplotlib 是一个强大的 Python 绘图库,广泛用于数据可视化。在 Matplotlib 中,网格线是一种常用的辅助工具,用于增强图表的可读性和美观性。本文将详细介绍如何在 Matplotlib 中添加和使用网格线。 1. 简介 网格线是在…...

钉钉机器人禅道消息通知@指派人
钉钉、禅道怎么设置webhook? 点击查看:获取自定义机器人 Webhook 地址 在禅道上配置钉钉机器人webhook,使用管理员账号登录,找到通知设置 添加webhook 添加webhook所需要的数据即可 webhook设置,根据自己的实际…...

我的新书出版啦!和大家聊聊写书的酸甜苦辣
我的新书出版啦!小伙伴们问是不是赚翻了? 大家好,我是码哥。我的新书《Redis 高手心法》出版后(2024 年 8 月份出版),有一些小伙伴问了我一些问题: 写书是不是赚了很多钱?我也想写…...

【福建医科大学附属第一医院-注册安全分析报告】
前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞 …...

第二届新生程序设计竞赛热身赛(C语言)
A:饥饿的XP XP迷失在X星球,他醒来时已经很久很久很久没有吃过东西了。他突然发现身边有一张地图,上面有X星球上每一个食物供给点的位置。太好了,XP跳了起来。他决定先把肚子填饱再去寻找其他伙伴。现在已知XP的位置(X, Y),以及他的…...

WebSocket和HTTP请求的区别
1. 连接方式 HTTP请求:基于“请求-响应”模式。每次通信都要重新建立连接,客户端发送请求后服务器返回响应,连接就断开了。这种模式通常适合不频繁更新的数据,如静态页面的加载。WebSocket:支持长连接,连接…...

【Python · Pytorch】人工神经网络 ANN(中)
【Python Pytorch】人工神经网络 ANN(中) 6. 反向传播6.1 梯度下降法6.1.1 线搜索方法6.1.2 微分 & 导数6.1.3 偏导数6.1.4 Jacobian矩阵6.1.5 梯度 & 梯度下降法按维度介绍 6.1.6 面临挑战平原现象 & 振荡现象局部最小值鞍点梯度消失梯度爆…...

穷举vs暴搜vs深搜vs回溯vs剪枝 算法专题
一. 全排列 全排列 class Solution {List<List<Integer>> ret;List<Integer> path;boolean[] check;public List<List<Integer>> permute(int[] nums) {ret new ArrayList<>();//存放结果path new ArrayList<>();存放每个路径的…...

Uni-App-02
条件编译 条件编译概念 不同的运行平台终归有些专有的特性,无法实现跨平台完全兼容,例如:微信小程序导航栏右上角的关闭图标。 uni-app提供了一种“条件编译”机制,可以针对特定的平台编译执行特定的代码,否则不执行。…...

在做题中学习(72):最小栈
解法:pair<int,int>解决 思路:stack里存pair,push时,first存当前值,而每次push都要更新pair的second,使它成为更小值,最后的getmin,只用取top().second即可拿到最小值。 cla…...

详解软件设计中分库分表的几种实现以及应用示例
详解软件设计中分库分表的几种实现以及应用示例https://mp.weixin.qq.com/s?__bizMzkzMTY0Mjc0Ng&mid2247485108&idx1&sn8b3b803c120c163092c70fa65fe5541e&chksmc266aaa1f51123b7af4d7a3113fe7c25daa938a04ced949fb71a8b7773e861fb93d907435386#rd...

随着飞行汽车的亮相,在环保方面有什么保护措施吗
飞行汽车具备环保潜力,采用电动或混合动力系统减少污染,并拓展应用场景。多家企业布局,沃飞长空作为国内eVTOL(电动垂直起降航空器)研发的领先企业,在环保这一点做的非常到位,AE200采用纯电动力系统,零碳排放,静默飞行…...

docker安装、设置非sudo执行、卸载
安装 sudo snap install docker 设置docker非sudo执行 sudo groupadd docker sudo usermod -aG docker $USER newgrp docker sudo chown root:docker /var/run/docker.sock 卸载docker 1.删除docker及安装时自动安装的所有包 apt-get autoremove docker docker-ce docker-…...

WebSocket简单使用
1.WebSocket 简介 WebSocket 是一种网络通信协议,提供了在单个TCP连接上进行全双工通信的能力。这意味着客户端和服务器可以同时发送和接收数据,而不需要等待对方的回应。WebSocket 协议在2011年成为国际标准,并且被大多数现代浏览器所支持。…...

【FinalShell问题】FinalShell连接虚拟机超时问题
问题描述: 打开fianlshell连接之前设置好的SSH连接(Linux),结果连接不上,并出现提示:java.net.ConnectException: Connection timed out: connect,说明虚拟机连接超时。 问题解决:…...

Matplotlib可视化——三维图与莫比乌斯带可视化
实验名称 Matplotlib中的三维图绘制:莫比乌斯带的可视化 实验目标 三维的点和线三维轮廓图线框图和曲面图曲面三角形 举例:莫比乌斯带的可视化实验主要使用的Python库 名称版本简介Numpy1.19.5数组运算Matplotlib3.3.4数据可视化实验适用的对象 学习对象:本科学生、研究生…...

【PyCharm配置Conda的虚拟环境】
conda create了一个新的虚拟环境,想在PyCharm里面使用这个环境,但是怎么都添加不上。 解决办法,把conda executable选择为conda安装目录下的condabin下的conda.bat文件,成功!...

今日总结10.31
BIO、NIO 和 AIO 的区别 BIO(Blocking I/O,同步阻塞I/O)、NIO(Non-blocking I/O,同步非阻塞I/O)和AIO(Asynchronous I/O,异步非阻塞I/O)是Java中的三种不同的I/O模型&am…...

2024年【汽车修理工(高级)】考试题及汽车修理工(高级)最新解析
题库来源:安全生产模拟考试一点通公众号小程序 2024年【汽车修理工(高级)】考试题及汽车修理工(高级)最新解析,包含汽车修理工(高级)考试题答案和解析及汽车修理工(高级…...

17. 从尾到头打印链表
文章目录 QuestionIdeasCode Question 输入一个链表的头结点,按照 从尾到头 的顺序返回节点的值。 返回的结果用数组存储。 数据范围0≤链表长度 ≤1000。 样例 输入:[2, 3, 5] 返回:[5, 3, 2] Ideas 直接遍历链表,然后倒序…...

有没有噪音低的宠物空气净化器推荐?希喂、IAM性能PK
有一说一,随着清洁家电市场的不断发展,市面上的各种清洁家电品类也是越来越多,像是吸尘器、洗地机、扫地机等等这些产品估计大家都很熟悉了。 但!如果你家也跟我家一样也是养了几只猫猫狗狗,那你就会发现到࿰…...

EasyExcel文件导入与导出
EasyExcel是一个为了简化Excel操作而生的开源库,它可以帮助我们以简洁的代码完成Excel文件的导入和导出。 以下是使用EasyExcel进行文件导入和导出的示例代码: 导入(读取)Excel文件: import com.alibaba.excel.Easy…...

【成都新篇】龙信科技电子取证实验室,引领科技取证新时代
文章关键词:电子数据取证实验室、手机取证、介质取证、云取证、现场勘查、电子物证 在科技创新的浪潮中,龙信科技成都实验室以其卓越的电子数据取证服务,成为了中西部地区一颗璀璨的明珠。随着新址的搬迁,我们不仅扩大了业务范围…...

Android View
前面我们了解了Android四大组件的工作流程,Android中还存在一个和四大组件地位相同的概念:View,用于向用户页面展示内容。我们经常使用的TextView、Button、ImageView控件等都继承于它,也会自定义View实现自定义效果。View类源码内…...

从一到无穷大 #38:讨论 “Bazel 集成仅使用 Cmake 的依赖项目” 通用方法
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作),由 李兆龙 确认,转载请注明版权。 文章目录 正文样例代码 正文 Bazel项目引用仅使用Cmake依赖项目,目前业界最为普遍…...

Python飞舞蝙蝠
目录 系列文章 写在前面 完整代码 代码分析 写在后面 系列文章 序号直达链接爱心系列1Python制作一个无法拒绝的表白界面2Python满屏飘字表白代码3Python无限弹窗满屏表白代码4Python李峋同款可写字版跳动的爱心5Python流星雨代码6Python漂浮爱心代码7Python爱心光波代码…...