密码加密解密之路

1.背景

做数据采集,客户需要把他们那边的数据库连接信息存到我们系统里,那我们系统就要尽可能的保证这部分数据安全,不被盗。

2.我的思路

1.需要加密的地方有两处,一个是新增的时候前端传给后端的时候,一个是存到数据库

2.与前端交互时的加密方式肯定和存到数据库的加密方式不同(为了安全)

3.接收前端传值,这块好说,跟前端约定一个加密方式,约定一个盐

4.存到数据库怎么加密解密

麻烦得点就在于存到数据库这里,

我是针对每一条数据都会生成一个uuid,然后nacos配置文件中还有一个盐salt

然后我把uuid和salt用特殊符号拼接之后,再进行一次加密形成最终盐 finalSalt

用finalSalt对密码进行加密,把密文密码存到数据库

如果用户对密码进行修改,那就重新生成一个uuid,再重新加密,存储密文

之所以设计这么麻烦,就是增加解密得困难度,想要明文,只有同时拿到数据库数据,nacos配置,以及我的java代码,才能解密,尽可能保障密码得安全性

5.密码可为空

这一点我是纠结了一会,因为在产品设计上密码是可为空得,如果我不把密码返回给前端,那前端保存得时候,如果用户没修改密码,前端上传给我得也会是空,那这个时候我就不知道到底是用户把密码改为空了,还是说他根本没有动密码这个文本框

所以我就把密文密码返回了,让他保存到时候再按照前后端约定加密传输给我,

我接收到之后先按照前后端约定得解密,再去和数据里边密文对比,

如果一致,说明没改,

如果不一致,说明修改了,并且解密出来的是明文密码,我会对明文密码按照4中说的再进行加密

但是把密文密码传给前端始终是个不太安全得事情

我后来想到一点,前端是可以识别到,用户是否动过密码这个文本框得

那我就不把密码返回给前端了

可以让前端给我一个标识,true,就代表动过文本框,

如果现在上传得密码为空,且动过文本框,那我就直接把密码字段保存为空即可。

如果现在上传得密码为空,但是false,没动过文本框,那我就不更新密码这个字段

如果现在上传密码不为空,那就不管true还是false了,密码肯定修改了,就先按照前后端解密再按照数据库加密即可

3.加解密工具类

这是针对数据库那一部分

博客上是前后端约定的那一部分

【精选】java前后端加密解密crypto-js_java crypto-CSDN博客


import org.apache.commons.codec.binary.Base64;
import org.springframework.util.StringUtils;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;

/**
 * @Description: 加密解密
 * @Version 1.0
 */
public class SecretUtil {

    
    
    /**
     * 用uuid加密
     *
     * @param UUID
     * @param salt     盐 从nacos配置中取值
     * @param password 明文密码
     * @return
     */
    public static String encryptUUID(String UUID, String salt, String password) {
        if (!StringUtils.hasText(UUID) || !StringUtils.hasText(salt) || !StringUtils.hasText(password)) {
            return null;
        }
        //先把uuid和salt再进行一次加密
        String concat = UUID.concat(salt);
        byte[] bytes = base64Encrypt(concat);
        //再对明文密码进行加密
        return encrypt(password, bytes);
    }

    /**
     * UUID解密
     *
     * @param UUID
     * @param salt     盐 从nacos配置中取值
     * @param password 密文密码
     * @return
     */
    public static String decryptUUID(String UUID, String salt, String password) {
        if (!StringUtils.hasText(UUID) || !StringUtils.hasText(salt) || !StringUtils.hasText(password)) {
            return null;
        }
        //先把uuid和salt再进行一次加密
        String concat = UUID.concat(salt);
        byte[] bytes = base64Encrypt(concat);
        //再对明文密码进行加密
        return decrypt(password, bytes);
    }

    /**
     * base64加密
     *
     * @param content 待加密内容
     * @return byte[]
     */
    public static byte[] base64Encrypt(final String content) {
        return java.util.Base64.getEncoder().encode(content.getBytes());
    }

    /**
     * base64解密
     *
     * @param encoderContent 已加密内容
     * @return byte[]
     */
    public static byte[] base64Decrypt(final byte[] encoderContent) {
        return java.util.Base64.getDecoder().decode(encoderContent);
    }

    /**
     * 加密
     *
     * @param data  待加密内容
     * @param bytes 盐的base64
     * @return
     */
    public static String encrypt(String data, byte[] bytes) {
        byte[] dataByte = data.getBytes(StandardCharsets.UTF_8);
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            secureRandom.setSeed(bytes);
            //这个128要特别注意  对长度有要求的
            keyGenerator.init(128, secureRandom);
            SecretKey secretKey = keyGenerator.generateKey();
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] encrypted = cipher.doFinal(dataByte);
            // 加密
            return java.util.Base64.getEncoder().encodeToString(encrypted);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }


    }

    /**
     * 解密
     *
     * @param data  待解密内容
     * @param bytes 盐的base64
     * @return
     */
    public static String decrypt(String data, byte[] bytes) {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            secureRandom.setSeed(bytes);
            //这个128要特别注意  对长度有要求的
            keyGenerator.init(128, secureRandom);
            SecretKey secretKey = keyGenerator.generateKey();
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(secretKey.getEncoded(), "AES"));
            //采用base64算法进行转码,避免出现中文乱码
            byte[] encryptBytes = Base64.decodeBase64(data);
            byte[] decryptBytes = cipher.doFinal(encryptBytes);
            return new String(decryptBytes);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


}

4.代码混淆

这块可以不看,是中间调研,走过的一个弯路

因为java的class文件可以反编译,所以我想让编译之后的代码变成01001那种无法识别的语言

但是发现java代码混淆并不能达成这个效果

但是毕竟走了一天弯路,还是记录下吧

4.1先看效果

4.2再上代码

从这下载吧

https://download.csdn.net/download/qq_35653822/88554123

里边有个字典,可以实现把包名,类名,变量名混淆为0o00o这种方式

5.不可逆算法

目前接触到的,存登录密码是不可逆算法,用的是security自带的加密

security提供了match方法,可以对比输入的密码和数据库中是否一致,返回true或者false,但是不提供解密方法

除非管理员可以一键重置用户的密码,把用户密码重置成初始化默认密码

存数据库里边的长这样,谁也看不出来存的是啥

 这种方法固然安全,但是对于我们1中说的需求,不适合这种算法,因为我们使用对方数据库的时候肯定要获取这个密码进行连接

    public static String irreversibleEncrypt(String password) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        //加密  每次调用加密方法 返回的结果都不同
        return passwordEncoder.encode(password);
    }

    /**
     * 对比
     * 不可逆算法 不能解密 只能对比
     *
     * @param oldPassword     未加密密码 如123456
     * @param requestPassword 加密后的密码
     * @return
     */
    public static boolean irreversibleMatch(String oldPassword, String requestPassword) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        //对比
        return passwordEncoder.matches(oldPassword, requestPassword);
    }

6.不对称算法

这个什么时候使用就看具体场景吧

7.keystore

Java密码术 - 存储密钥( Storing keys)_学习Java密码学|WIKI教程

这个同事调研过,结论是不适合我们,我没仔细研究

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/169501.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL 之多版本并发控制 MVCC

MySQL 之多版本并发控制 MVCC 1、MVCC 中的两种读取方式1.1、快照读1.2、当前读 2、MVCC实现原理之 ReadView2.1、隐藏字段2.2、ReadView2.3、读已提交和可重复读隔离级别下,产生 ReadView 时机的区别 3、MVCC 解决幻读4、总结 MVCC(多版本并发控制&…

公网环境下使用VNC远程连接Ubuntu系统桌面

文章目录 前言1. ubuntu安装VNC2. 设置vnc开机启动3. windows 安装VNC viewer连接工具4. 内网穿透4.1 安装cpolar【支持使用一键脚本命令安装】4.2 创建隧道映射4.3 测试公网远程访问 5. 配置固定TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址5.3 测试…

基于变形卷积和注意机制的带钢表面缺陷快速检测网络DCAM-Net(论文阅读笔记)

原论文链接->DCAM-Net: A Rapid Detection Network for Strip Steel Surface Defects Based on Deformable Convolution and Attention Mechanism | IEEE Journals & Magazine | IEEE Xplore DCAM-Net: A Rapid Detection Network for Strip Steel Surface Defects Base…

基于Qt中操作MySQL数据库示例

# 一、安装驱动 ##(1)安装 在Qt中操作MySQL数据库首先要安装mysql的驱动文件,将MySQL下的libmusql.dll文件复制到Qt的安装路径下的bin文件夹下即可。 直接将libmysql.dll文件粘贴到此文件夹中。 ## (2)验证驱动是否安装成功 复制成功之后来测试一下驱动程序是否安装成功…

轻松实现公网访问本地内网搭建的WBO白板【内网穿透】

文章目录 前言1. 部署WBO白板2. 本地访问WBO白板3. Linux 安装cpolar4. 配置WBO公网访问地址5. 公网远程访问WBO白板6. 固定WBO白板公网地址7. 结语 前言 WBO在线协作白板是一个自由和开源的在线协作白板,允许多个用户同时在一个虚拟的大型白板上画图。该白板对所有…

Harmony Ble 蓝牙App (一)扫描

Harmony Ble 蓝牙App (一)扫描 前言正文一、创建工程二、工程配置① 权限配置② Debug配置③ UI配置 三、扫描① 扫描接口② 扫描类 四、业务处理① Slice的生命周期② 蓝牙开关和动态权限请求 五、扫描设备六、显示设备① 自定义蓝牙类② 提供者③ 显示…

【EI会议征稿】第三届能源利用与自动化国际学术会议(ICEUA 2024)

第三届能源利用与自动化国际学术会议(ICEUA 2024) 2024 3rd International Conference on Energy Utilization and Automation (ICEUA 2024) 2024年第三届能源利用与自动化国际学术会议(ICEUA 2024)将于2024年3月15-17日在中国武汉…

细说MySQL数据类型

TOC 目录 MySQL数据类型 数据类型分类 数值类型 tinyint类型 有符号tinyint范围测试 无符号tinyint范围测试 bit类型 bit类型的显示方式 bit类型的范围测试 float类型 有符号float范围测试 无符号float范围测试 decimal类型 字符串类型 char类型 char类型测试 …

微服务架构中的 熔断和降级

文章目录 熔断判定服务的健康状态服务恢复正常 降级跨服务降级自身服务提供有损服务具体案例分析 熔断 微服务架构中,如果需要保障可用性,其中一个方式就是 熔断。熔断在微服务架构里面是指 当微服务本身出现问题的时候,它会拒绝新的请求&am…

关于RecyclerView的瀑布流 分割线左右间距问题

记录一下开发遇到的RecyclerView 的 瀑布流 左右间距设置问题。 在GridLayoutManager中 ,item的布局顺序为 在该布局中,他的index就是左右左右,position所对应的itemView就是准确的。即 左0,右1,左2,右3&a…

建议收藏《Verilog代码规范笔记_华为》

华为verilog编程规范是坊间流传出来华为内部的资料,其贴合实际工作需要,是非常宝贵的资料,希望大家善存。至于其介绍,在此不再赘述,大家可看下图详细了解,感兴趣的可私信移知教育老师领取《Verilog代码规范…

Colab跑项目

这里写目录标题 Colab文件目录路径显示更改colab当前工作文件夹Colab挂载谷歌云盘colab使用命令(从这开始看,前面no zuo no die)最紧要,首先,修改笔记本设置使用启用gpu![在这里插入图片描述](https://img-blog.csdnimg.cn/591a6c…

qsort

qsort void*修饰后pv不能1&#xff0c;-1也不能解引用 例子 /* qsort example */ #include <stdio.h> /* printf */ #include <stdlib.h> /* qsort */int values[] { 40, 10, 100, 90, 20, 25 };int compare (const void * a, const void * b) {return…

指针变量和地址

A.指针变量和地址 理解了内存和地址的关系&#xff0c;我们再回到C语⾔&#xff0c;在C语⾔中创建变量其实就是向内存申请空间&#xff0c;比如&#xff1a; #include <stdio.h> int main() {int a 10;return 0; } ⽐如&#xff0c;上述的代码就是创建了整型变量a&…

Threejs_05 几何体顶点索引

Threejs中的任何一个几何体都是由若干个索引点构成的&#xff0c;然后这些索引点其实构成的都是三个坐标的三角形。 使用顶点坐标构建几何体 1.我们需要一个支持几何体属性的物料 //创建几何体(三角形) const geometry new THREE.BufferGeometry(); 2.构造一个顶点坐标组 …

51单片机直流电机控制

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pwm波形&#xff1f;1.1高低电平交互&#xff0c;LED亮灭。1.2 驱动电机时&#xff1f;1.3 怎么调节电机的速度&#xff1f; 二、怎么用51单片机产生PWM波形…

OpenVPN Connect使用连接公网VPN服务器实现内网穿透

安装并运行OpenVPN Connect 点击AGREE 添加配置.OVPN文件 点击连接 连接成功 两个内网主机通过公网VPN穿透

哪些软件可以监控电脑(保姆级教程!值得收藏!)

今天了解到了一个软件&#xff0c;真的把我吓到了。 我才知道原来我上班时摸鱼时多么愚蠢的一件事情。原来老板可以通过一些软件轻而易举的知道你用电脑做的所有事情&#xff0c;怪不得我每次摸鱼时老板看我的眼神都不对…… 安装好域之盾软件以后&#xff0c;打开就能监控你使…

电容的耐压值是什么意思呢?

电容是什么&#xff1f; 电容是一种能以电荷的形式储存能量的装置。与同样大小的电池相比&#xff0c;电容能储存的能量要小得多&#xff0c;大约1w个电容存储的能量才顶一节电池存储的能量&#xff0c;但对于许多电路设计来说却足够使用了。 看下图的直插式电容&#xff0c;…

竞赛 题目:基于深度学习的中文汉字识别 - 深度学习 卷积神经网络 机器视觉 OCR

文章目录 0 简介1 数据集合2 网络构建3 模型训练4 模型性能评估5 文字预测6 最后 0 简介 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的中文汉字识别 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &a…