加密与安全_优雅存储二要素(AES-256-GCM )

文章目录

  • 什么是二要素
  • 如何保护二要素(姓名和身份证)
    • 加密算法分类
    • 场景选择
    • 算法选择
      • AES - ECB 模式 (不推荐)
      • AES - CBC 模式
      • GCM(Galois/Counter Mode)
        • AES-256-GCM简介
        • AES-256-GCM工作原理
        • 安全优势
      • 应用场景
      • 其他模式 和 敏感数据加密建议
  • Code

在这里插入图片描述


什么是二要素

二要素(姓名和身份证)是敏感数据,,很多网站仅仅依靠二要素来确认你是谁,若以明文形式存储在数据库中,存在被攻破的风险。若这些信息被不法分子获取, 后果严重。


如何保护二要素(姓名和身份证)

单向散列算法,如MD5、SHA-256等,虽然可以对数据生成唯一的指纹,但由于其不可逆,无法用于加密需要解密的数据。因此,它不适合用于对二要素信息(如姓名和身份证)进行加密保存。

在此情况下,需要选择真正的加密算法来实现数据的加密存储与解密。

加密算法分类

  1. 对称加密算法

    • 对称加密算法依赖于一个相同的密钥,既用于加密,也用于解密。常见的对称加密算法包括AES、DES、3DES等。
    • 在通信场景中,加密方和解密方必须事先共享密钥,双方才能进行加密和解密。密钥的共享过程是该加密方式的关键挑战之一,因为如果密钥在传输过程中被窃取或泄露,加密数据就容易被解密,安全性将大打折扣。
    • 优点:对称加密的主要优势在于加密和解密的速度非常快,特别适合需要高效处理大量数据的场景。
    • 缺点:密钥分发的安全性是对称加密的主要隐患。如果在通信中,密钥传输不当导致泄露,攻击者可以利用该密钥轻松解密数据。
  2. 非对称加密算法

    • 非对称加密算法由一对密钥构成,分别为公钥(加密密钥)和私钥(解密密钥)。常见的非对称加密算法有RSA、DSA等。
    • 公钥可以任意公开,而私钥必须保持私密。使用公钥加密的数据只能由对应的私钥解密。因此,通信双方只需共享公钥即可,无需直接传输私钥,从而避免了密钥泄露的问题。
    • 优点:非对称加密解决了密钥分发的安全性问题,适合用在双方未建立密钥共享机制的场景。
    • 缺点:加密和解密的速度相对较慢,特别是在处理大数据量时性能不足。

场景选择

在需要加密保存二要素信息的场景下,加密和解密都是由同一个服务端程序执行,双方并不需要通过网络传输密钥,因此密钥分发的安全性问题不是关键点。相对而言,对称加密算法具有速度快、效率高的优势,更适合在服务端加密存储二要素数据

因此,尽管非对称加密在解决密钥传输安全性上有独特优势,但在保存敏感数据的场景中,采用对称加密算法(如AES-CBC或AES-CTR模式)更为合适。

算法选择

对称加密常用算法有 DES3DESAES

  • DES 已被证明不安全,破解时间很短,不推荐使用。
  • 3DES 通过三次 DES 串联调用解决了 DES 的安全性问题,但速度较慢,也不推荐使用。
  • AES 是目前公认安全且高效的算法,采用 Rijndael 作为标准。

AES 是目前较为主流的对称加密算法,兼具高安全性和高性能。AES 是由 NIST 选拔出的 Rijndael 算法作为标准,支持分组加密模式。AES 每次处理 128 位明文,生成相应的 128 位密文。对于较长的明文,需要通过分组迭代加密。

AES - ECB 模式 (不推荐)

在这里插入图片描述

加密一段包含 16 个字符的字符串,得到密文 A;然后把这段字符串复制一份成为一个32 个字符的字符串,再进行加密得到密文 B。我们验证下密文 B 是不是重复了一遍的密文 A。

模拟银行转账的场景,假设整个数据由发送方账号、接收方账号、金额三个字段构成。我们尝试改变密文中数据的顺序来操纵明文

   private static final String KEY = "secretkey1234567";

   @GetMapping("ecb")
    public void ecb() throws Exception {
        Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
        test(cipher, null);
    }


   private static SecretKeySpec setKey(String secret) {
        return new SecretKeySpec(secret.getBytes(), "AES");
    }


   private static void test(Cipher cipher, AlgorithmParameterSpec parameterSpec) throws Exception {
	        cipher.init(Cipher.ENCRYPT_MODE, setKey(KEY), parameterSpec);
	        System.out.println("一次:" + Hex.encodeHexString(cipher.doFinal("abcdefghijklmnop".getBytes())));
	        System.out.println("两次:" + Hex.encodeHexString(cipher.doFinal("abcdefghijklmnopabcdefghijklmnop".getBytes())));
	        byte[] sender = "1000000000012345".getBytes();
	        byte[] receiver = "1000000000034567".getBytes();
	        byte[] money = "0000000010000000".getBytes();
	
	        //加密发送方账号
	        System.out.println("发送方账号:" + Hex.encodeHexString(cipher.doFinal(sender)));
	        //加密接收方账号
	        System.out.println("接收方账号:" + Hex.encodeHexString(cipher.doFinal(receiver)));
	        //加密金额
	        System.out.println("金额:" + Hex.encodeHexString(cipher.doFinal(money)));
	        byte[] result = cipher.doFinal(ByteUtils.concatAll(sender, receiver, money));
	        //加密三个数据
	        System.out.println("完整数据:" + Hex.encodeHexString(result));
	        byte[] hack = new byte[result.length];
	        //把密文前两段交换
	        System.arraycopy(result, 16, hack, 0, 16);
	        System.arraycopy(result, 0, hack, 16, 16);
	        System.arraycopy(result, 32, hack, 32, 16);
	        cipher.init(Cipher.DECRYPT_MODE, setKey(KEY), parameterSpec);
	        //尝试解密
	        System.out.println("原始明文:" + new String(ByteUtils.concatAll(sender, receiver, money)));
	        System.out.println("操纵密文:" + new String(cipher.doFinal(hack)));
	    }

输出

一次:a6025aaadd429e8c13073fc3512a7250
两次:a6025aaadd429e8c13073fc3512a7250a6025aaadd429e8c13073fc3512a7250
发送方账号:fdfc03515d95e2fa33edc9ca67cf43ae
接收方账号:e70eecf4baa8decf117d294e12d850c0
金额:f317ed23783f4babb607bd88ba076d0c
完整数据:fdfc03515d95e2fa33edc9ca67cf43aee70eecf4baa8decf117d294e12d850c0f317ed23783f4babb607bd88ba076d0c
原始明文:100000000001234510000000000345670000000010000000
操纵密文:100000000003456710000000000123450000000010000000

如上代码示例展示了 ECB 模式的漏洞,攻击者可以在不解密的情况下操纵密文,实现对敏感数据(如银行转账信息)的修改。 -----> 在不知道密钥的情况下,我们操纵密文实现了对明文数据的修改,对调了发送方账号和接收方账号

原始明文:100000000001234510000000000345670000000010000000
操纵密文:100000000003456710000000000123450000000010000000

代码运行的结果证明了:

  • 重复的明文生成相同的密文。

  • 攻击者可以通过调换密文分组的顺序,达到修改明文数据的效果。

  • 重复性问题:如果明文中有重复的分组,密文中也会出现重复,这会暴露明文的模式,存在规律性。

  • 独立分组问题:每个分组独立加密和解密,攻击者可以通过交换密文分组的顺序来操控明文内容。

因此,ECB 模式简单但不安全,不推荐使用。


AES - CBC 模式

CBC 模式,在解密或解密之前引入了 XOR 运算,第一个分组使用外部提供的初始化向量IV,从第二个分组开始使用前一个分组的数据,这样即使明文是一样的,加密后的密文也是不同的,并且分组的顺序不能任意调换。这就解决了 ECB 模式的缺陷.

在这里插入图片描述

把之前的代码修改为 CBC 模式,再次进行测试

 private static final String initVector = "abcdefghijklmnop";


 @GetMapping("cbc")
    public void cbc() throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
        IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
        test(cipher, iv);
    }

可以看到,相同的明文字符串复制一遍得到的密文并不是重复两个密文分组,并且调换密文分组的顺序无法操纵明文。

一次:6fa7a7b2c0979abecc1b59fe17b663c6
两次:6fa7a7b2c0979abecc1b59fe17b663c6e873cb4abb4b46b76cb748447373103c
发送方账号:ff4f74de614be6905951fa2ac68a529a
接收方账号:0dfdd3116d26dac4a7349167dfa0ce0a
金额:5521773b79160a1a51b9d8f8bfb0a346
完整数据:ff4f74de614be6905951fa2ac68a529abb54065906129619b122c978541f0076347086b16d09934e4f9d9dc4ab942af0
原始明文:100000000001234510000000000345670000000010000000
SD�A�x�%B[3t+B�Wi@��Cb��b�

GCM(Galois/Counter Mode)

AES-256-GCM简介

GCM(Galois/Counter Mode)是一种结合计数器模式(Counter Mode)和Galois域认证的分组加密模式。它不仅能够提供高效的加密服务,还能实现消息认证(即验证消息的完整性和真实性)。与传统的CBC模式不同,GCM模式可以并行处理,极大提升了性能,特别适合高吞吐量的环境。

这是一种 AEADAuthenticated Encryption with Associated Data)认证加密算法,除了能实现普通加密算法提供的保密性之外,还能实现可认证性和密文完整性,是目前最推荐的 AES 模式。

使用类似 GCM 的 AEAD 算法进行加解密,除了需要提供初始化向量和密钥之外,还可以提供一个 AAD(附加认证数据,additional authenticated data),用于验证未包含在明文中的附加信息,解密时不使用加密时的 AAD 将解密失败。其实,GCM 模式的内部使用的就是 CTR 模式,只不过还使用了 GMAC 签名算法,对密文进行签名实现完整性校验。


AES-256-GCM工作原理

AES-256-GCM结合了AES-256加密算法和GCM模式,具备如下功能:

  • 加密:数据通过AES-256加密算法被加密。
  • 消息认证码(MAC):在加密的同时,GCM模式会生成一个128位的消息认证码,用于验证数据的完整性和真实性。这一特性可以防止数据被篡改。
  • 附加数据:GCM支持附加认证数据(AAD),这部分数据不会被加密,但会被用于认证。例如,网络协议中的头部信息可以作为AAD进行保护。
安全优势

相较于其他常见的模式,如CBC(Cipher Block Chaining),AES-256-GCM提供了显著的优势:

  • 并行处理:GCM模式允许多线程并行处理,加速了加密和解密过程,非常适合高性能需求的场景。
  • 集成认证:GCM不仅加密数据,还生成认证标签,保证数据的完整性和真实性。相比之下,像CBC这样的模式需要单独实现消息认证。
  • 防御重放攻击:GCM模式通过计数器的设计,有效防止了重放攻击和其他类似的攻击手段。

应用场景

AES-256-GCM的广泛应用场景包括:

  • TLS/SSL加密:TLS 1.3推荐使用AES-GCM模式进行数据加密,以确保网络通信的安全性。
  • VPN:许多VPN协议(如IPSec)使用AES-256-GCM进行数据传输加密。
  • 云存储加密:云服务供应商在存储敏感数据时经常采用AES-256-GCM,以确保数据的安全性和完整性。

其他模式 和 敏感数据加密建议

除了 ECB 模式外,AES 还有 CBCCFBOFBCTR 模式。推荐使用 CBCCTR 模式。ECB 和 CBC 模式需要设置合适的填充方式来处理超过一个分组的数据。

此外,对于敏感数据加密,建议:

  1. 不要在代码中写死密钥或初始化向量(IV),应确保密钥和 IV 唯一、独立、且每次都变化。
  2. 使用独立的加密服务来管理密钥,避免将密钥与密文存储在同一个数据库中,确保加密服务有严格的管控标准。
  3. 数据库中不应保存明文敏感信息,可以存储脱敏数据,并在普通查询时使用脱敏信息。

Code

接下来,我们按照如上策略完成相关代码实现:

第一步,对于用户姓名和身份证,我们分别保存三个信息,脱敏后的明文、密文和加密ID。加密服务加密后返回密文和加密 ID,随后使用加密 ID 来请求加密服务进行解密

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.Id;

@Data
@Entity
public class UserData {
    @Id
    private Long id;
    private String idcard;//脱敏的身份证
    private Long idcardCipherId;//身份证加密ID
    private String idcardCipherText;//身份证密文
    private String name;//脱敏的姓名
    private Long nameCipherId;//姓名加密ID
    private String nameCipherText;//姓名密文
}


第二步,加密服务数据表保存加密 ID、初始化向量和密钥。加密服务表中没有密文,实现了密文和密钥分离保存.

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import static javax.persistence.GenerationType.AUTO;

@Data
@Entity
public class CipherData {
    @Id
    @GeneratedValue(strategy = AUTO)
    private Long id;
    private String iv;//初始化向量
    private String secureKey;//密钥
}


第三步,加密服务使用 GCM 模式( Galois/Counter Mode)的 AES-256 对称加密算法,也就是 AES-256-GCM

接下来,我们实现基于 AES-256-GCM 的加密服务,包含下面的主要逻辑:

  • 加密时允许外部传入一个 AAD 用于认证,加密服务每次都会使用新生成的随机值作为密钥和初始化向量。
  • 在加密后,加密服务密钥和初始化向量保存到数据库中,返回加密 ID 作为本次加密的标识。
  • 应用解密时,需要提供加密 ID、密文和加密时的 AAD 来解密。加密服务使用加密 ID,从数据库查询出密钥和初始化向量。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Base64;

@Service
public class CipherService {
    //密钥长度
    public static final int AES_KEY_SIZE = 256;
    //初始化向量长度
    public static final int GCM_IV_LENGTH = 12;
    //GCM身份认证Tag长度
    public static final int GCM_TAG_LENGTH = 16;
    @Autowired
    private CipherRepository cipherRepository;

    //内部加密方法
    public static byte[] doEncrypt(byte[] plaintext, SecretKey key, byte[] iv, byte[] aad) throws Exception {
        //加密算法
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        //Key规范
        SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "AES");
        //GCM参数规范
        GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
        //加密模式
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec);
        //设置aad
        if (aad != null)
            cipher.updateAAD(aad);
        //加密
        byte[] cipherText = cipher.doFinal(plaintext);
        return cipherText;
    }

    //内部解密方法
    public static String doDecrypt(byte[] cipherText, SecretKey key, byte[] iv, byte[] aad) throws Exception {
        //加密算法
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        //Key规范
        SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "AES");
        //GCM参数规范
        GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
        //解密模式
        cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);
        //设置aad
        if (aad != null)
            cipher.updateAAD(aad);
        //解密
        byte[] decryptedText = cipher.doFinal(cipherText);
        return new String(decryptedText);
    }

    //加密入口
    public CipherResult encrypt(String data, String aad) throws Exception {
        //加密结果
        CipherResult encryptResult = new CipherResult();
        //密钥生成器
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        //生成密钥
        keyGenerator.init(AES_KEY_SIZE);
        SecretKey key = keyGenerator.generateKey();
        //IV数据
        byte[] iv = new byte[GCM_IV_LENGTH];
        //随机生成IV
        SecureRandom random = new SecureRandom();
        random.nextBytes(iv);
        //处理aad
        byte[] aaddata = null;
        if (!StringUtils.isEmpty(aad))
            aaddata = aad.getBytes();
        //获得密文
        encryptResult.setCipherText(Base64.getEncoder().encodeToString(doEncrypt(data.getBytes(), key, iv, aaddata)));
        //加密上下文数据
        CipherData cipherData = new CipherData();
        //保存IV
        cipherData.setIv(Base64.getEncoder().encodeToString(iv));
        //保存密钥
        cipherData.setSecureKey(Base64.getEncoder().encodeToString(key.getEncoded()));
        cipherRepository.save(cipherData);
        //返回本地加密ID
        encryptResult.setId(cipherData.getId());
        return encryptResult;
    }

    //解密入口
    public String decrypt(long cipherId, String cipherText, String aad) throws Exception {
        //使用加密ID找到加密上下文数据
        CipherData cipherData = cipherRepository.findById(cipherId).orElseThrow(() -> new IllegalArgumentException("invlaid cipherId"));
        //加载密钥
        byte[] decodedKey = Base64.getDecoder().decode(cipherData.getSecureKey());
        //初始化密钥
        SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
        //加载IV
        byte[] decodedIv = Base64.getDecoder().decode(cipherData.getIv());
        //处理aad
        byte[] aaddata = null;
        if (!StringUtils.isEmpty(aad))
            aaddata = aad.getBytes();
        //解密
        return doDecrypt(Base64.getDecoder().decode(cipherText.getBytes()), originalKey, decodedIv, aaddata);
    }
}

第四步,分别实现加密和解密接口用于测试。

可以让用户选择,如果需要保护二要素的话,就自己输入一个查询密码作为 AAD。系统需要读取用户敏感信息的时候,还需要用户提供这个密码,否则无法解密。这样一来,即使黑客拿到了用户数据库的密文、加密服务的密钥和 IV,也会因为缺少 AAD 无法解密.

 @Autowired
 private CipherService cipherService;

 // 加密 
 @GetMapping("right")
    public UserData right(@RequestParam(value = "name", defaultValue = "小工匠") String name,
                          @RequestParam(value = "idcard", defaultValue = "300000000000001234") String idCard,
                          @RequestParam(value = "aad", required = false) String aad) throws Exception {
        UserData userData = new UserData();
        userData.setId(1L);
        //脱敏姓名
        userData.setName(chineseName(name));
        //脱敏身份证
        userData.setIdcard(idCard(idCard));
        //加密姓名
        CipherResult cipherResultName = cipherService.encrypt(name, aad);
        userData.setNameCipherId(cipherResultName.getId());
        userData.setNameCipherText(cipherResultName.getCipherText());
        //加密身份证
        CipherResult cipherResultIdCard = cipherService.encrypt(idCard, aad);
        userData.setIdcardCipherId(cipherResultIdCard.getId());
        userData.setIdcardCipherText(cipherResultIdCard.getCipherText());
        return userRepository.save(userData);
    }


	// 解密 
   @GetMapping("read")
    public void read(@RequestParam(value = "aad", required = false) String aad) throws Exception {
        UserData userData = userRepository.findById(1L).get();
        log.info("name : {} idcard : {}",
                cipherService.decrypt(userData.getNameCipherId(), userData.getNameCipherText(), aad),
                cipherService.decrypt(userData.getIdcardCipherId(), userData.getIdcardCipherText(), aad));

    }

  // 脱敏身份证
   private static String idCard(String idCard) {
        String num = StringUtils.right(idCard, 4);
        return StringUtils.leftPad(num, StringUtils.length(idCard), "*");
    }

 // 脱敏姓名
    public static String chineseName(String chineseName) {
        String name = StringUtils.left(chineseName, 1);
        return StringUtils.rightPad(name, StringUtils.length(chineseName), "*");
    }


启动服务,访问 http://localhost:45678/storeidcard/right

在这里插入图片描述

访问解密接口: http://localhost:45678/storeidcard/read
在这里插入图片描述

如果AAD错误

在这里插入图片描述

经过这样的设计,二要素就比较安全了。黑客要查询用户二要素的话,需要同时拿到密文、IV+ 密钥、AAD。而这三者可能由三方掌管,要全部拿到比较困难。

在这里插入图片描述

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

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

相关文章

AIoT智能工控板

在当今竞争激烈的商业环境中,企业需要强大的科技力量来助力腾飞,AIoT智能工控板就是这样的力量源泉。 其领先的芯片架构设计,使得主板的性能得到了极大的提升。无论是数据的处理速度、图形的渲染能力,还是多任务的并行处理能力&a…

Ceph官方文档_01_Ceph简介

目录 Ceph介绍Ceph介绍 Ceph可用于向云平台提供Ceph对象存储,Ceph可用于向云平台提供Ceph块设备服务。Ceph可用于部署Ceph文件系统。所有Ceph存储群集部署开始都是先设置每个Ceph节点,然后再设置网络。 Ceph存储集群需要以下内容:至少一个Ceph监视器和至少一个Ceph管理器,…

毕业设计选题:基于ssm+vue+uniapp的捷邻小程序

开发语言:Java框架:ssmuniappJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:M…

Linux top命令详解与重点内容说明

文章目录 重点说明基本信息进程(任务)信息cpu占用信息%Cpu(s)内存信息交换内存信息每列含义说明交互命令多窗口模式颜色配置命令参数 重点说明 top命令非常强大,也非常复杂,很难面面俱到,也没有必要,这篇文章的目的是介绍重点&am…

en造数据结构与算法C# 群组行为优化 和 头鸟控制

实现: 1.给鸟类随机播放随机动画使得每一只鸟扇翅膀的频率都不尽相同 2.可以自行添加权重,并在最后 sumForce separationForce cohesionForce alignmentForce;分别乘上相应权重,这样鸟就能快速飞行和转向辣 using System.Collections.Ge…

Linux系统编程(基础指令)上

1.Linux常见目录介绍 Linux目录为树形结构 /:根目录,一般根目录下只存放目录,在Linux下有且只有一个根目录。所有的东西都是从这里开始。当你在终端里输入“/home”,你其实是在告诉电脑,先从/(根目录&…

Unity3D入门(二) :Unity3D实现视角的丝滑过渡切换

1. 前言 上篇文章,我们已经初步了解了Unity3D,并新建并运行起来了一个项目,使相机视角自动围绕着立方体旋转。 这篇文章,我们来讲一下Unity3D怎么过渡地切换视角。 我们继续是我上篇文章中的项目,但是需要向把Camera…

​OpenAI最强模型o1系列:开启人工智能推理新时代

前不久OpenAI发布全新模型——o1模型,也就是业界说的“草莓模型”,包含三款型号:OpenAI o1、OpenAI o1-preview和OpenAI o1-mini。 其中,OpenAI o1-mini和 o1-preview已经对用户开放使用: OpenAI o1:高级推…

企业急于采用人工智能,忽视了安全强化

对主要云提供商基础设施上托管的资产的安全分析显示,许多公司为了急于构建和部署 AI 应用程序而打开安全漏洞。常见的发现包括对 AI 相关服务使用默认且可能不安全的设置、部署易受攻击的 AI 软件包以及不遵循安全强化指南。 这项分析由 Orca Security 的研究人员进…

Redis学习以及SpringBoot集成使用Redis

目录 一、Redis概述 二、Linux下使用Docker安装Redis 三、SpringBoot集成使用Redis 3.1 添加redis依赖 3.2 配置连接redis 3.3 实现序列化 3.4 注入RedisTemplate 3.5 测试 四、Redis数据结构 一、Redis概述 什么是redis? redis 是一个高性能的&#xf…

vue项目加载cdn失败解决方法

注释index.html文件中 找到vue.config.js文件注释、

【Python语言初识(二)】

一、分支结构 1.1、if语句 在Python中,要构造分支结构可以使用if、elif和else关键字。所谓关键字就是有特殊含义的单词,像if和else就是专门用于构造分支结构的关键字,很显然你不能够使用它作为变量名(事实上,用作其他…

0基础带你入门Linux之使用

1.Ubuntu软件管理 回顾一下,我们之前使用su root切换到root模式,使用who 发现为什么显示的还是bd用户呢?为什么呢? 这个who是主要来查看的是我们登录的时候是以什么用户登录的 所以即使我们使用who进行查看的时候显示的还是bd用…

【JavaWeb】利用IDEA2024+tomcat10配置web6.0版本搭建JavaWeb开发项目

之前写过一篇文章:《【JavaWeb】利用IntelliJ IDEA 2024.1.4 Tomcat10 搭建Java Web项目开发环境(图文超详细)》详细讲解了如何搭建JavaWeb项目的开发环境,里面默认使用的Web版本是4.0版本的。但在某些时候tomcat10可能无法运行we…

提升效率的AI工具集 - 轻松实现自动化

在这个快节奏、高效率的社会中,我们每个人都渴望能够找到提升工作效率的捷径。幸运的是,随着人工智能(AI)技术的迅猛发展,越来越多的AI工具涌现出来,为我们提供了强大的支持。这些工具不仅能够帮助我们提高…

计算机毕业设计 美发管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…

尚品汇-秒杀成功下单接口、秒杀结束定时任务-清空缓存数据(五十四)

目录: (1)下单页面 (2)service-activity-client添加接口 (3)web-all 编写去下单控制器 (4)service-order模块提供秒杀下单接口 (5)service-or…

安全基础学习-AES128加密算法

前言 AES(Advanced Encryption Standard)是对称加密算法的一个标准,主要用于保护电子数据的安全。AES 支持128、192、和256位密钥长度,其中AES-128是最常用的一种,它使用128位(16字节)的密钥进…

推荐系统-电商直播 多目标排序算法探秘

前言: 电商直播已经成为电商平台流量的主要入口,今天我们一起探讨推荐算法在直播中所面临的核心问题和解决方案。以下内容参考阿里1688的技术方案整理完成。 一、核心问题介绍 在电商网站中,用户的主要行为是在商品上的行为,直播…

机器学习笔记(一)初识机器学习

1.定义 机器学习是一门多学科交叉专业,涵盖概率论知识,统计学知识,近似理论知识和复杂算法知识,使用计算机作为工具并致力于真实实时的模拟人类学习方式,并将现有内容进行知识结构划分来有效提高学习效率。 机器学习有…