密码加密解密之路

news2024/11/16 1:24:07

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教程

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浅析RSA非对称加密算法

目录 引言 凯撒密码 对称加密 非对称加密 ​编辑总结 引言 几月前在知乎上看到一个关于RSA公钥与私钥加解密的提问甚感兴趣,却一直没有时间去探究,今日浅得闲时以文记之。 在文章正式开始之前先讲一个小故事,在公元前58年时&#xff0c…

css 实现文字流光效果

经过调研发现大多滑块验证码中,有一些文字流光效果,因此在这里简单实现一下。 实现主要利用background 渐变背景以及backgorund-clip:text实现。具体代码如下 css部分 .slide {width: 300px;height: 40px;border: 1px solid #ccc;border-radius: 8px;…

猫12分类:使用yolov5训练检测模型

前言: 在使用yolov5之前,尝试过到百度飞桨平台(小白不建议)、AutoDL平台(这个比较友好,经济实惠)训练模型。但还是没有本地训练模型来的舒服。因此远程了一台学校电脑来搭建自己的检测模型。配置…

【鸿蒙最新全套教程】<HarmonyOS第一课>1、运行Hello World

下载与安装DevEco Studio 在HarmonyOS应用开发学习之前,需要进行一些准备工作,首先需要完成开发工具DevEco Studio的下载与安装以及环境配置。 进入DevEco Studio下载官网,单击“立即下载”进入下载页面。 DevEco Studio提供了Windows版本和…

pyQt主界面与子界面切换简易框架

本篇来介绍使用python中是Qt功能包,设置一个简易的多界面切换框架,实现主界面和多个子界面直接的切换显示。 1 主界面 设计的Demo主界面如下,主界面上有两个按钮图标,点击即可切换到对应的功能界面中,进入子界面后&a…

猫12分类:使用多线程爬取图片的Python程序

本文目标 对于猫12目标检测部分的数据集,采用网络爬虫来制作数据集。 在网络爬虫中,经常需要下载大量的图片。为了提高下载效率,可以使用多线程来并发地下载图片。本文将介绍如何使用Python编写一个多线程爬虫程序,用于爬取图片…

飞翔的小鸟

运行游戏如下: 碰到柱子就结束游戏 App GameApp类 package App;import main.GameFrame;public class GameApp {public static void main(String[] args) {//游戏的入口new GameFrame();} } main Barrier 类 package main;import util.Constant; import util.Ga…

Linux--网络编程

一、网络编程概述1.进程间通信: 1)进程间通信的方式有**:管道,消息队列,共享内存,信号,信号量这么集中 2)特点:依赖于linux内核,基本是通过内核来实现应用层…

线上bug-接口速度慢

👽System.out.println(“👋🏼嗨,大家好,我是代码不会敲的小符,双非大四,Java实习中…”); 📚System.out.println(“🎈如果文章中有错误的地方,恳请大家指正&a…

十四、Docker的基本操作

目录 (一)镜像命令 一、拉取Nginx 二、查看镜像 三、导出文件 四、删除镜像 五、加载镜像 (二)容器命令 一、例子:运行一个nginx容器 1、输入运行命令 2、使用命令查看宿主机ip 3、在外部浏览器访问 4、查看…

函数调用分析

目录 函数相关的汇编指令 JMP指令 call指令 ret指令 VS2019正向分析main函数 总结调用函数堆栈变化规律 x64dbg分析调用函数 IDA分析调用函数 函数相关的汇编指令 JMP指令 JMP 指令表示的是需要跳转到哪个内存地址,相当于是间接修改了 EIP 。 call指令 ca…

NX二次开发UF_CAM_ask_blank_matl_db_object 函数介绍

文章作者:里海 来源网站:里海NX二次开发3000例专栏 UF_CAM_ask_blank_matl_db_object Defined in: uf_cam.h int UF_CAM_ask_blank_matl_db_object(UF_CAM_db_object_t * db_obj ) overview 概述 This function provides the database object which …

使ros1和ros2的bag一直互通

很多文章都是先source ros1 然后source ros2,再play bag source /opt/ros/noetic/setup.bash source /opt/ros/foxy/setup.bash ros2 bag play -s rosbag_v2 kitti_raw00.bag 但实测会出问题: 为使ros1和ros2的bag一直互通 sudo apt update sudo apt install ros-foxy-ro…

axios的原理及实现一个简易版axios

面试官:你了解axios的原理吗?有看过它的源码吗? 一、axios的使用 关于axios的基本使用,上篇文章已经有所涉及,这里再稍微回顾下: 发送请求 import axios from axios;axios(config) // 直接传入配置 axio…

hdfsClient_java对hdfs进行上传、下载、删除、移动、打印文件信息尚硅谷大海哥

Java可以通过Hadoop提供的HDFS Java API来控制HDFS。通过HDFS Java API,可以实现对HDFS的文件操作,包括文件的创建、读取、写入、删除等操作。 具体来说,Java可以通过HDFS Java API来创建一个HDFS文件系统对象,然后使用该对象来进…

PPT幻灯片里的图片,批量提取

之前分享过如何将PPT文件导出成图片,今天继续分享PPT技巧,如何提取出PPT文件里面的图片。 首先,我们将PPT文件的后缀名,修改为rar,将文件改为压缩包文件 然后我们将压缩包文件进行解压 最好是以文件夹的形式解压出来…

车载毫米波雷达行业发展1——概述

1.1 毫米波雷达定义及产品演进 1.1.1 毫米波雷达定义 毫米波雷达(mmWave Radar)是指工作在毫米波波段的雷达,其频域介于 30~300GHz,波长1~10mm。毫米波雷达稳定性高,抗干扰能力强,可穿透雾、烟、灰尘环境&#xff0…

发币成功,记录一下~

N年前就听说了这样一种说法——“一个熟练的区块链工程师,10分钟就可以发出一个新的币” 以前仅仅是有这么一个认识,但当时并不特别关注这个领域。 最近系统性学习中,今天尝试发币成功啦,记录一下~ 发在 Sepolia Tes…

CentOS7安装部署Kafka with KRaft

文章目录 CentOS7安装部署Kafka with KRaft一、前言1.简介2.架构3.环境 二、正文1.部署服务器2.基础环境1)主机名2)Hosts文件3)关闭防火墙4)JDK 安装部署 3.单机部署1)下载软件包2)修改配置文件3&#xff0…

[Genode] ARM TrustZone

这是关于读文章ARM TrustZone的记录,原文是英文,刚开始会有点反应不过来,这里大部分是对文章的翻译与提取。 ARM信任区技术 ARM信任区是在 热烈讨论关于X86平台上的可信平台模块(TPM) 时引入的。。 就像TPM芯片神奇…