敏感数据加密存储实战

敏感数据加密存储实战

一、敏感数据概述

敏感数据是指一旦泄露可能造成安全风险的信息,需要采取加密措施保护。

1.1 敏感数据分类

类别 示例 加密要求
个人身份 身份证号、手机号 必须加密
金融信息 银行卡号、密码 必须加密
业务敏感 用户密码、Token 必须加密
配置信息 密钥、证书 必须加密

1.2 加密策略

复制代码
┌─────────────────────────────────────────────────────────────┐
│                     敏感数据加密流程                        │
├─────────────────────────────────────────────────────────────┤
│  数据输入 ──▶ 明文 ──▶ 加密 ──▶ 密文 ──▶ 存储              │
│       │                                   │                │
│       │                                   ▼                │
│       └──────────────── 解密 ◀───────────┘                │
│                                       │                    │
│                                       ▼                    │
│                                    明文输出                 │
└─────────────────────────────────────────────────────────────┘

二、加密算法选择

2.1 对称加密

java 复制代码
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class SymmetricEncryption {
    
    private static final String ALGORITHM = "AES";
    private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding";
    
    public static String encrypt(String plainText, String key) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), ALGORITHM);
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        byte[] encrypted = cipher.doFinal(plainText.getBytes());
        return Base64.getEncoder().encodeToString(encrypted);
    }
    
    public static String decrypt(String cipherText, String key) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), ALGORITHM);
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(cipherText));
        return new String(decrypted);
    }
}

2.2 非对称加密

java 复制代码
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import javax.crypto.Cipher;

public class AsymmetricEncryption {
    
    private static final String ALGORITHM = "RSA";
    
    public static KeyPair generateKeyPair() throws Exception {
        KeyPairGenerator generator = KeyPairGenerator.getInstance(ALGORITHM);
        generator.initialize(2048);
        return generator.generateKeyPair();
    }
    
    public static byte[] encrypt(byte[] data, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }
    
    public static byte[] decrypt(byte[] data, PrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }
}

2.3 混合加密方案

java 复制代码
public class HybridEncryption {
    
    public static EncryptedData encrypt(String plainText, PublicKey publicKey) throws Exception {
        // 生成对称密钥
        String symmetricKey = generateRandomKey(16);
        
        // 使用对称密钥加密数据
        String encryptedData = SymmetricEncryption.encrypt(plainText, symmetricKey);
        
        // 使用公钥加密对称密钥
        byte[] encryptedKey = AsymmetricEncryption.encrypt(symmetricKey.getBytes(), publicKey);
        
        return new EncryptedData(encryptedData, encryptedKey);
    }
    
    public static String decrypt(EncryptedData encryptedData, PrivateKey privateKey) throws Exception {
        // 使用私钥解密对称密钥
        byte[] symmetricKey = AsymmetricEncryption.decrypt(encryptedData.getEncryptedKey(), privateKey);
        
        // 使用对称密钥解密数据
        return SymmetricEncryption.decrypt(encryptedData.getEncryptedData(), new String(symmetricKey));
    }
}

三、数据库加密

3.1 字段级加密

java 复制代码
@Entity
public class User {
    
    @Id
    private Long id;
    
    @Column(name = "username")
    private String username;
    
    @Column(name = "password")
    @Convert(converter = EncryptedStringConverter.class)
    private String password;
    
    @Column(name = "email")
    @Convert(converter = EncryptedStringConverter.class)
    private String email;
}

@Converter
public class EncryptedStringConverter implements AttributeConverter<String, String> {
    
    @Override
    public String convertToDatabaseColumn(String attribute) {
        if (attribute == null) return null;
        try {
            return SymmetricEncryption.encrypt(attribute, getSecretKey());
        } catch (Exception e) {
            throw new RuntimeException("Encryption failed", e);
        }
    }
    
    @Override
    public String convertToEntityAttribute(String dbData) {
        if (dbData == null) return null;
        try {
            return SymmetricEncryption.decrypt(dbData, getSecretKey());
        } catch (Exception e) {
            throw new RuntimeException("Decryption failed", e);
        }
    }
}

3.2 数据库透明加密

yaml 复制代码
# MySQL TDE配置
innodb_encrypt_tables = ON
innodb_encryption_threads = 4
innodb_encrypt_log = ON
innodb_encryption_rotate_key_age = 1

3.3 密码哈希

java 复制代码
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class PasswordUtil {
    
    private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
    
    public static String hashPassword(String rawPassword) {
        return encoder.encode(rawPassword);
    }
    
    public static boolean verifyPassword(String rawPassword, String encodedPassword) {
        return encoder.matches(rawPassword, encodedPassword);
    }
}

四、密钥管理

4.1 密钥存储

java 复制代码
@Configuration
public class KeyManagementConfig {
    
    @Bean
    public String secretKey() {
        // 从密钥管理服务获取密钥
        return keyManagementService.getSecret("app-encryption-key");
    }
}

4.2 密钥轮换

java 复制代码
public class KeyRotationService {
    
    public void rotateKey() {
        // 生成新密钥
        String newKey = generateRandomKey(32);
        
        // 更新密钥存储
        keyManagementService.updateSecret("app-encryption-key", newKey);
        
        // 重新加密所有数据(可选)
        reEncryptAllData(newKey);
    }
}

4.3 使用密钥管理服务

java 复制代码
public class CloudKeyManager {
    
    private final AWSKMS kmsClient;
    
    public byte[] encryptWithKms(byte[] data) {
        EncryptRequest request = EncryptRequest.builder()
                .keyId("arn:aws:kms:us-east-1:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab")
                .plaintext(data)
                .build();
        
        return kmsClient.encrypt(request).ciphertextBlob().array();
    }
}

五、安全传输

5.1 HTTPS配置

yaml 复制代码
server:
  port: 443
  ssl:
    enabled: true
    key-store: classpath:keystore.p12
    key-store-password: ${KEY_STORE_PASSWORD}
    key-store-type: PKCS12
    key-alias: myapp

5.2 TLS证书管理

bash 复制代码
# 使用Let's Encrypt获取证书
certbot certonly --webroot -w /var/www/html -d example.com

# 自动续期
certbot renew --dry-run

六、文件加密

6.1 文件加密工具

java 复制代码
public class FileEncryption {
    
    public static void encryptFile(String inputPath, String outputPath, String key) throws Exception {
        try (FileInputStream fis = new FileInputStream(inputPath);
             FileOutputStream fos = new FileOutputStream(outputPath);
             CipherOutputStream cos = new CipherOutputStream(fos, getCipher(Cipher.ENCRYPT_MODE, key))) {
            
            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                cos.write(buffer, 0, bytesRead);
            }
        }
    }
    
    public static void decryptFile(String inputPath, String outputPath, String key) throws Exception {
        try (FileInputStream fis = new FileInputStream(inputPath);
             CipherInputStream cis = new CipherInputStream(fis, getCipher(Cipher.DECRYPT_MODE, key));
             FileOutputStream fos = new FileOutputStream(outputPath)) {
            
            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = cis.read(buffer)) != -1) {
                fos.write(buffer, 0, bytesRead);
            }
        }
    }
}

七、脱敏处理

7.1 数据脱敏

java 复制代码
public class DataMaskingUtil {
    
    public static String maskPhone(String phone) {
        if (phone == null || phone.length() < 11) return phone;
        return phone.substring(0, 3) + "****" + phone.substring(7);
    }
    
    public static String maskIdCard(String idCard) {
        if (idCard == null || idCard.length() < 18) return idCard;
        return idCard.substring(0, 4) + "**********" + idCard.substring(14);
    }
    
    public static String maskEmail(String email) {
        if (email == null || !email.contains("@")) return email;
        String[] parts = email.split("@");
        if (parts[0].length() <= 2) return email;
        return parts[0].substring(0, 2) + "****@" + parts[1];
    }
}

7.2 日志脱敏

java 复制代码
@Aspect
public class LogMaskingAspect {
    
    @Around("execution(* com.example..*.*(..))")
    public Object maskLog(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = joinPoint.proceed();
        // 对日志输出进行脱敏处理
        maskSensitiveData(result);
        return result;
    }
}

八、安全审计

8.1 访问日志

java 复制代码
@Configuration
public class AuditLogConfig {
    
    @Bean
    public Filter auditFilter() {
        return (request, response, chain) -> {
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            
            AuditLog log = AuditLog.builder()
                    .userId(getUserId(httpRequest))
                    .action(httpRequest.getRequestURI())
                    .method(httpRequest.getMethod())
                    .ip(getClientIp(httpRequest))
                    .timestamp(LocalDateTime.now())
                    .build();
            
            auditLogRepository.save(log);
            chain.doFilter(request, response);
        };
    }
}

8.2 数据变更审计

java 复制代码
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
public abstract class Auditable {
    
    @CreatedBy
    @Column(name = "created_by")
    private String createdBy;
    
    @CreatedDate
    @Column(name = "created_date")
    private LocalDateTime createdDate;
    
    @LastModifiedBy
    @Column(name = "last_modified_by")
    private String lastModifiedBy;
    
    @LastModifiedDate
    @Column(name = "last_modified_date")
    private LocalDateTime lastModifiedDate;
}

九、合规要求

9.1 GDPR合规

java 复制代码
public class GdprService {
    
    public void rightToBeForgotten(Long userId) {
        // 删除用户所有数据
        userRepository.deleteById(userId);
        
        // 删除相关日志
        auditLogRepository.deleteByUserId(userId);
        
        // 删除缓存数据
        redisTemplate.delete("user:" + userId);
    }
    
    public void dataPortability(Long userId) {
        // 导出用户所有数据
        UserData data = exportUserData(userId);
        
        // 提供下载
        sendDataExport(data);
    }
}

9.2 数据分类分级

级别 描述 保护措施
L1 公开数据 无需加密
L2 内部数据 访问控制
L3 敏感数据 加密存储
L4 机密数据 加密+访问审计

十、总结

敏感数据加密存储需要综合考虑:

  1. 选择合适算法:对称加密用于数据,非对称加密用于密钥
  2. 密钥安全管理:使用专业密钥管理服务
  3. 多层防护:传输加密、存储加密、访问控制
  4. 合规审计:满足GDPR等法规要求
  5. 定期轮换:定期更换密钥,降低泄露风险

通过系统化的加密策略,可以有效保护敏感数据的安全。

相关推荐
兰令水1 小时前
topcode【随机算法题】【2026.5.22打卡-java版本】
java·算法·leetcode
夕除1 小时前
spring boot 12
java·开发语言·python
罗超驿1 小时前
21.jdbc 学习笔记:从原理到实践的全流程梳理
java·数据库·mysql·面试
Mahir081 小时前
Spring 全家桶常见注解全解:从入门到精通
java·后端·spring·面试·常见注解
执笔论英雄1 小时前
GPU内存架构-DSMEM与L2
java·spring·架构
wb043072011 小时前
从 Java 1 到 Java 26 的HTTP Client发展历程
java·开发语言·http
小则又沐风a1 小时前
进一步了解进程---第四章 进程管理
java·服务器·前端
超梦dasgg2 小时前
并查集(Union-Find)详解 + Java 完整实现
java·数据结构·算法·图搜索
WL_Aurora2 小时前
Java集合框架核心组件
java