加密与安全_前后端通过AES-CBC模式安全传输数据

文章目录


Pre

加密与安全_解密AES加密中的IV和Seed

加密与安全_双向RSA+AES加密及Code实现

加密与安全_常见的分组密码 ECB、CBC、CFB、OFB模式介绍


概述

当我们在前端和后端之间传输敏感信息时,安全性变得越来越重要。今天,我们将一起探索如何在前端加密密码,并在后端安全解密的过程。

使用Vue.js作为前端框架,并通过Java来处理后端解密。


前端加密是否有意义?

前端加密是否真的有意义?其实,这个问题的答案并不绝对。

  • 一方面,前端加密能够一定程度上防止中间人攻击,从而保护用户的隐私。
  • 但另一方面,如果攻击者能够篡改前端代码,前端加密就形同虚设。

因此,前端加密到底值不值得,还是见仁见智。


环境准备

前端使用的是Vue.js,也可以选择纯JS。同时,我们引入crypto-js库。至于后端,Java将担任这次任务的重任。

为了让前端和后端能够顺利交流,我们必须确保前后端使用相同的加密方式、模式(MODE)和填充方式(PADDING)


加密方法、MODE和PADDING的选择

加密方法、MODE和PADDING之间也必须配合得天衣无缝。前后端的这些参数必须一致,才能确保传输的信息能够正确加密和解密。

必须选择前后端都支持的加密方法、模式和填充方式。

https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html

https://cryptojs.gitbook.io/docs/#pbkdf2


以下是\选择的参数:

  • 加密方法: AES(推荐加密方法,参考:FIPS 197
  • 模式: CBC(默认模式,参考:FIPS 81
  • 填充方式: Pkcs7(与Java的PKCS5Padding基本等价)

在这里,我们选择AES/CBC/Pkcs7作为加密组合,而Java端则使用AES/CBC/PKCS5Padding。这样一来,我们的前后端就可以在同一个频道上交流了。


前端

需要引入crypto-js库,并设置好密钥(key)和初始向量(iv)。这些设置必须与后端保持一致,才能确保加密与解密的正确性。

javascript 复制代码
// aesutils.js
import CryptoJs from 'crypto-js'

// 把key、iv设置成固定值,前后端的值要一致
let key = CryptoJs.enc.Utf8.parse("xxxxxx");
let iv = CryptoJs.enc.Utf8.parse("yyyyyy");

export function Encrypt(word) {
    let srcs = CryptoJs.enc.Utf8.parse(word);
    var encrypted = CryptoJs.AES.encrypt(srcs, key, {
        iv: iv,
        mode: CryptoJs.mode.CBC,
        padding: CryptoJs.pad.Pkcs7
    });
    return CryptoJs.enc.Base64.stringify(encrypted.ciphertext);
}

在这个加密函数中,我们将原始文本转换为Base64编码后的密文,然后将其发送到后端。如此一来,前端的密码在传输过程中便不会以明文形式暴露。


后端

后端的任务是接收到前端传来的密文,并将其解密为原始的明文密码。这一步同样至关重要,因为后端需要将这些密码存储或用于后续操作。

java 复制代码
import org.apache.tomcat.util.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

public class AESUtils {

    private static final String key = "xxxxxx";
    private static final String iv = "yyyyyy";

    public static String deocdeStr(String text) {
        try {
            byte[] encrypted = new Base64().decode(text);

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding ");
            SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
            IvParameterSpec ivParameter = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));

            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameter);

            byte[] decrypted = cipher.doFinal(encrypted);
            String originalString = new String(decrypted, StandardCharsets.UTF_8);
            return originalString;
        } catch (Exception e) {
            return e.toString();
        }
    }
}

后端解密的核心步骤与前端加密紧密关联。首先,我们将Base64编码的密文解码为字节数组,然后利用AES/CBC/PKCS5Padding的组合将其解密为原始字符串。


应用:从传输到解密的全过程

在前端,我们使用工具类加密密码,然后通过axios等方法将加密后的密文传输到后端:

javascript 复制代码
import { Encrypt } from "@/utils/aesutils";

Encrypt(this.$data.formData.password);

在后端,接收到加密的密文后,我们调用工具类解密并还原密码,然后将其用于后续的数据库操作:

java 复制代码
 
AESUtils.deocdeStr(user.getPassword());

安全性增强

尽管我们使用了固定的密钥和初始向量(IV),但在实际的生产环境中,这种方式的安全性可能还不够强。接下来,我们将进一步提升安全性,探索如何使用动态生成的密钥和初始向量,并研究在生产环境中如何更好地管理这些关键要素。

动态生成密钥和初始向量

使用固定的密钥和IV,虽然简化了前后端的协调工作,但也带来了风险。一旦密钥和IV被泄露,攻击者就可以轻松解密传输的数据。为了解决这个问题,我们可以采取动态生成密钥和IV的方法。

1. 前端:动态生成密钥和IV

在前端,我们可以在每次需要加密时,动态生成密钥和IV。然后,将密钥和IV与加密后的数据一起发送到后端。为了避免密钥和IV直接暴露在网络传输中,我们可以将它们与加密数据一起加密或使用安全的密钥交换算法。

javascript 复制代码
import CryptoJs from 'crypto-js';

// 生成随机密钥和IV
function generateKeyAndIV() {
    let key = CryptoJs.lib.WordArray.random(128 / 8); // 128-bit key
    let iv = CryptoJs.lib.WordArray.random(128 / 8);  // 128-bit IV
    return { key, iv };
}

// 加密函数
export function encryptWithDynamicKey(word) {
    const { key, iv } = generateKeyAndIV();
    let srcs = CryptoJs.enc.Utf8.parse(word);
    let encrypted = CryptoJs.AES.encrypt(srcs, key, {
        iv: iv,
        mode: CryptoJs.mode.CBC,
        padding: CryptoJs.pad.Pkcs7
    });

    // 将密钥和IV与加密后的数据一起编码
    return {
        ciphertext: CryptoJs.enc.Base64.stringify(encrypted.ciphertext),
        key: CryptoJs.enc.Base64.stringify(key),
        iv: CryptoJs.enc.Base64.stringify(iv)
    };
}

generateKeyAndIV函数生成了一个随机的密钥和IV。然后,我们将这些随机生成的密钥和IV与加密后的数据一起编码并发送给后端。

2. 后端:解密动态密钥和IV

在后端接收到加密数据和动态生成的密钥、IV后,我们需要解码并使用它们进行解密操作。

java 复制代码
import org.apache.tomcat.util.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

public class AESUtils {

    public static String decryptWithDynamicKey(String ciphertext, String keyBase64, String ivBase64) {
        try {
            byte[] encrypted = new Base64().decode(ciphertext);
            byte[] key = new Base64().decode(keyBase64);
            byte[] iv = new Base64().decode(ivBase64);

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
            IvParameterSpec ivParameter = new IvParameterSpec(iv);

            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameter);

            byte[] decrypted = cipher.doFinal(encrypted);
            return new String(decrypted, StandardCharsets.UTF_8);
        } catch (Exception e) {
            return e.toString();
        }
    }
}

这个解密函数接受Base64编码的密文、密钥和IV。我们先将它们解码为字节数组,然后使用它们来解密密文,恢复原始数据。


结语

通过动态生成密钥和初始向量,并使用安全的密钥管理服务,我们可以大幅提升系统的安全性。这不仅能防止密钥泄露带来的风险,还能通过安全的密钥交换和管理,确保前后端通信的绝对安全。

在实际的生产环境中,密钥的管理和轮换至关重要,建议使用专业的KMS来简化并加强密钥管理工作。通过这些措施,可以构建一个更加安全和稳健的系统 。

相关推荐
WTT00111 小时前
2024楚慧杯WP
大数据·运维·网络·安全·web安全·ctf
群联云防护小杜4 小时前
如何给负载均衡平台做好安全防御
运维·服务器·网络·网络协议·安全·负载均衡
ihengshuai4 小时前
HTTP协议及安全防范
网络协议·安全·http
黑客Jack5 小时前
防御 XSS 的七条原则
安全·web安全·xss
云云3216 小时前
怎么通过亚矩阵云手机实现营销?
大数据·服务器·安全·智能手机·矩阵
神一样的老师6 小时前
面向高精度网络的时间同步安全管理架构
网络·安全·架构
云云3218 小时前
云手机方案全解析
大数据·服务器·安全·智能手机·矩阵
云云3219 小时前
云手机能用来干什么?云手机在跨境电商领域的用途
服务器·线性代数·安全·智能手机·矩阵
云云3219 小时前
云手机方案总结
服务器·线性代数·安全·智能手机·矩阵
m0_748237059 小时前
2024年“羊城杯”粤港澳大湾区网络安全大赛 初赛 Web&数据安全&AI 题解WriteUp
前端·安全·web安全