档案管理系统数据加密实操指南:从零到一实现全流程保护

一、核心加密方案选择与设计

档案管理系统数据加密需要采用分层加密策略,针对不同数据类型和访问场景使用合适的加密技术。

1.1 数据库字段级加密

对于敏感字段(如身份证号、联系方式、薪资信息),采用AES-256-GCM算法进行字段级加密。GCM模式提供认证加密,防止密文被篡改。

加密密钥管理方案:使用三层密钥体系

  • 数据加密密钥(DEK):每个加密字段使用独立的随机生成密钥
  • 密钥加密密钥(KEK):用于加密DEK,存储在应用服务器内存中
  • 主密钥(MK):用于加密KEK,存储在硬件安全模块或密钥管理服务中

1.2 文件存储加密

对于上传的附件文件,采用服务端加密方式:

  • 小于100MB的文件:使用AES-256-CTR模式进行整体加密
  • 大于100MB的文件:使用分块加密,每块4MB,便于流式处理

二、环境准备与依赖安装

2.1 开发环境要求

操作系统:Linux (Ubuntu 20.04 LTS) 或 Windows Server 2019+

Java环境:OpenJDK 11+ 或 Oracle JDK 11+

数据库:MySQL 8.0+ 或 PostgreSQL 12+

2.2 加密库安装

对于Java项目,在pom.xml中添加以下依赖:

``` org.bouncycastle bcprov-jdk15on 1.70 com.github.ulisesbocchio jasypt-spring-boot-starter 3.0.5 ```

三、数据库字段加密实现

3.1 创建加密工具类

创建EncryptionUtils.java文件:

``` import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.util.Base64; public class EncryptionUtils { private static final String ALGORITHM = "AES/GCM/NoPadding"; private static final int TAG_LENGTH_BIT = 128; private static final int IV_LENGTH_BYTE = 12; public static String encrypt(String plaintext, String key) throws Exception { byte[] keyBytes = Base64.getDecoder().decode(key); SecretKey secretKey = new SecretKeySpec(keyBytes, "AES"); byte[] iv = new byte[IV_LENGTH_BYTE]; SecureRandom.getInstanceStrong().nextBytes(iv); Cipher cipher = Cipher.getInstance(ALGORITHM); GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, iv); cipher.init(Cipher.ENCRYPT_MODE, secretKey, spec); byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8)); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); outputStream.write(iv); outputStream.write(ciphertext); return Base64.getEncoder().encodeToString(outputStream.toByteArray()); } public static String decrypt(String encryptedText, String key) throws Exception { byte[] keyBytes = Base64.getDecoder().decode(key); SecretKey secretKey = new SecretKeySpec(keyBytes, "AES"); byte[] decoded = Base64.getDecoder().decode(encryptedText); byte[] iv = Arrays.copyOfRange(decoded, 0, IV_LENGTH_BYTE); byte[] ciphertext = Arrays.copyOfRange(decoded, IV_LENGTH_BYTE, decoded.length); Cipher cipher = Cipher.getInstance(ALGORITHM); GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, iv); cipher.init(Cipher.DECRYPT_MODE, secretKey, spec); byte[] plaintext = cipher.doFinal(ciphertext); return new String(plaintext, StandardCharsets.UTF_8); } } ```

3.2 配置数据源加密

在application.yml中配置Jasypt加密:

``` jasypt: encryptor: bean: jasyptStringEncryptor password: ${JASYPT_ENCRYPTOR_PASSWORD:defaultPassword} algorithm: PBEWithMD5AndDES iv-generator-classname: org.jasypt.iv.NoIvGenerator spring: datasource: url: ENC(加密后的数据库URL) username: ENC(加密后的用户名) password: ENC(加密后的密码) ```

生成加密配置值的命令:

``` java -cp jasypt-1.9.3.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="your_database_password" password="your_jasypt_password" algorithm=PBEWithMD5AndDES ```

四、文件加密存储实现

4.1 文件加密处理器

档案管理系统数据加密实操指南:从零到一实现全流程保护

创建FileEncryptionService.java:

``` @Service public class FileEncryptionService { private static final int BUFFER_SIZE = 4096; private static final String ALGORITHM = "AES/CTR/NoPadding"; public void encryptFile(Path inputFile, Path outputFile, String key) throws Exception { byte[] keyBytes = Base64.getDecoder().decode(key); SecretKey secretKey = new SecretKeySpec(keyBytes, "AES"); byte[] iv = new byte[16]; SecureRandom.getInstanceStrong().nextBytes(iv); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv)); try (InputStream in = Files.newInputStream(inputFile); OutputStream out = Files.newOutputStream(outputFile)) { // 写入IV out.write(iv); byte[] buffer = new byte[BUFFER_SIZE]; int bytesRead; while ((bytesRead = in.read(buffer)) != -1) { byte[] encrypted = cipher.update(buffer, 0, bytesRead); if (encrypted != null) { out.write(encrypted); } } byte[] finalEncrypted = cipher.doFinal(); if (finalEncrypted != null) { out.write(finalEncrypted); } } } public void decryptFile(Path inputFile, Path outputFile, String key) throws Exception { byte[] keyBytes = Base64.getDecoder().decode(key); SecretKey secretKey = new SecretKeySpec(keyBytes, "AES"); try (InputStream in = Files.newInputStream(inputFile); OutputStream out = Files.newOutputStream(outputFile)) { // 读取IV byte[] iv = new byte[16]; in.read(iv); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); byte[] buffer = new byte[BUFFER_SIZE]; int bytesRead; while ((bytesRead = in.read(buffer)) != -1) { byte[] decrypted = cipher.update(buffer, 0, bytesRead); if (decrypted != null) { out.write(decrypted); } } byte[] finalDecrypted = cipher.doFinal(); if (finalDecrypted != null) { out.write(finalDecrypted); } } } } ```

4.2 文件上传控制器

创建FileUploadController.java:

``` @RestController @RequestMapping("/api/files") public class FileUploadController { @Autowired private FileEncryptionService encryptionService; @PostMapping("/upload") public ResponseEntity uploadFile(@RequestParam("file") MultipartFile file) { try { // 生成文件存储路径 String originalFilename = file.getOriginalFilename(); String fileId = UUID.randomUUID().toString(); String encryptedFileName = fileId + ".enc"; Path tempFile = Files.createTempFile("upload_", ".tmp"); file.transferTo(tempFile); // 生成加密密钥 KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(256); SecretKey secretKey = keyGen.generateKey(); String base64Key = Base64.getEncoder().encodeToString(secretKey.getEncoded()); // 加密文件 Path encryptedFile = Paths.get("/data/encrypted_files", encryptedFileName); encryptionService.encryptFile(tempFile, encryptedFile, base64Key); // 保存密钥到数据库(需先加密存储) saveFileKey(fileId, base64Key); // 清理临时文件 Files.delete(tempFile); return ResponseEntity.ok(fileId); } catch (Exception e) { return ResponseEntity.status(500).body("文件上传失败"); } } private void saveFileKey(String fileId, String encryptedKey) { // 使用字段加密方法加密密钥后存储到数据库 String doubleEncryptedKey = EncryptionUtils.encrypt(encryptedKey, getMasterKey()); // 保存到file_keys表:file_id, encrypted_key, created_at } } ```

五、密钥安全管理

5.1 密钥生成与轮换

创建密钥管理服务KeyManagementService.java:

``` @Service public class KeyManagementService { private static final String KEY_STORE_PATH = "/etc/app/keystore.jceks"; private static final String MASTER_KEY_ALIAS = "master_key"; @PostConstruct public void init() throws Exception { File keyStoreFile = new File(KEY_STORE_PATH); if (!keyStoreFile.exists()) { generateMasterKey(); } } private void generateMasterKey() throws Exception { KeyStore keyStore = KeyStore.getInstance("JCEKS"); keyStore.load(null, null); KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(256); SecretKey masterKey = keyGen.generateKey(); KeyStore.SecretKeyEntry keyEntry = new KeyStore.SecretKeyEntry(masterKey); KeyStore.ProtectionParameter protection = new KeyStore.PasswordProtection("changeit".toCharArray()); keyStore.setEntry(MASTER_KEY_ALIAS, keyEntry, protection); try (FileOutputStream fos = new FileOutputStream(KEY_STORE_PATH)) { keyStore.store(fos, "storepass".toCharArray()); } // 设置文件权限 Files.setPosixFilePermissions(Paths.get(KEY_STORE_PATH), Set.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE)); } public String getMasterKey() throws Exception { KeyStore keyStore = KeyStore.getInstance("JCEKS"); try (FileInputStream fis = new FileInputStream(KEY_STORE_PATH)) { keyStore.load(fis, "storepass".toCharArray()); } KeyStore.ProtectionParameter protection = new KeyStore.PasswordProtection("changeit".toCharArray()); KeyStore.SecretKeyEntry keyEntry = (KeyStore.SecretKeyEntry) keyStore.getEntry(MASTER_KEY_ALIAS, protection); return Base64.getEncoder().encodeToString(keyEntry.getSecretKey().getEncoded()); } } ```

5.2 密钥轮换策略

创建密钥轮换脚本rotate_keys.sh:

``` !/bin/bash 密钥轮换脚本,每月1号凌晨2点执行 BACKUP_DIR="/backup/keys/$(date +%Y%m)" mkdir -p $BACKUP_DIR 备份当前主密钥 cp /etc/app/keystore.jceks $BACKUP_DIR/keystore_$(date +%Y%m%d).jceks 生成新的数据加密密钥 java -cp your-app.jar com.example.KeyRotator \ --action=rotate-data-keys \ --old-master-key=$(cat /etc/app/old_master.key) \ --new-master-key=$(cat /etc/app/new_master.key) 更新主密钥 mv /etc/app/new_master.key /etc/app/old_master.key ```

六、数据库表结构设计

6.1 加密字段表设计

创建加密字段映射表:

``` CREATE TABLE encrypted_fields ( id BIGINT PRIMARY KEY AUTO_INCREMENT, table_name VARCHAR(100) NOT NULL, column_name VARCHAR(100) NOT NULL, key_id VARCHAR(64) NOT NULL, encryption_algorithm VARCHAR(50) DEFAULT 'AES-256-GCM', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX idx_table_column (table_name, column_name) ); CREATE TABLE data_encryption_keys ( key_id VARCHAR(64) PRIMARY KEY, encrypted_key TEXT NOT NULL, key_version INT DEFAULT 1, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, expires_at TIMESTAMP NULL, is_active BOOLEAN DEFAULT TRUE ); ```

6.2 文件密钥表设计

创建文件密钥存储表:

``` CREATE TABLE file_encryption_keys ( file_id VARCHAR(36) PRIMARY KEY, encrypted_file_key TEXT NOT NULL, iv VARCHAR(32) NOT NULL, encryption_algorithm VARCHAR(50) DEFAULT 'AES-256-CTR', key_version INT DEFAULT 1, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX idx_created (created_at) ); ```

七、部署与监控配置

7.1 Docker部署配置

创建Dockerfile:

``` FROM openjdk:11-jre-slim RUN apt-get update && apt-get install -y \ openssl \ && rm -rf /var/lib/apt/lists/ COPY target/archive-system.jar /app.jar COPY keystore.jceks /etc/app/keystore.jceks RUN chmod 600 /etc/app/keystore.jceks RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /etc/app USER appuser EXPOSE 8080 ENTRYPOINT ["java", "-jar", "/app.jar"] ```

7.2 监控配置

在application.yml中添加监控端点:

``` management: endpoints: web: exposure: include: health,metrics,encryption endpoint: encryption: enabled: true health: show-details: always encryption: metrics: enabled: true encryption-operations: true key-rotation-events: true ```

创建加密监控指标:

``` @Component public class EncryptionMetrics { private final MeterRegistry meterRegistry; private final Counter encryptionCounter; private final Counter decryptionCounter; public EncryptionMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; this.encryptionCounter = Counter.builder("encryption.operations") .tag("type", "encrypt") .register(meterRegistry); this.decryptionCounter = Counter.builder("encryption.operations") .tag("type", "decrypt") .register(meterRegistry); } public void recordEncryption() { encryptionCounter.increment(); } public void recordDecryption() { decryptionCounter.increment(); } } ```

八、测试验证步骤

8.1 单元测试编写

创建加密测试类EncryptionTest.java:

``` @SpringBootTest public class EncryptionTest { @Autowired private EncryptionUtils encryptionUtils; @Test public void testFieldEncryption() throws Exception { String originalText = "410101199001011234"; String key = Base64.getEncoder().encodeToString( KeyGenerator.getInstance("AES").generateKey().getEncoded()); String encrypted = encryptionUtils.encrypt(originalText, key); String decrypted = encryptionUtils.decrypt(encrypted, key); assertEquals(originalText, decrypted); assertNotEquals(originalText, encrypted); } @Test public void testFileEncryption() throws Exception { Path originalFile = Files.createTempFile("test_", ".txt"); Files.write(originalFile, "测试文件内容".getBytes()); Path encryptedFile = Files.createTempFile("enc_", ".enc"); Path decryptedFile = Files.createTempFile("dec_", ".txt"); String key = Base64.getEncoder().encodeToString( KeyGenerator.getInstance("AES").generateKey().getEncoded()); FileEncryptionService service = new FileEncryptionService(); service.encryptFile(originalFile, encryptedFile, key); service.decryptFile(encryptedFile, decryptedFile, key); byte[] originalBytes = Files.readAllBytes(originalFile); byte[] decryptedBytes = Files.readAllBytes(decryptedFile); assertArrayEquals(originalBytes, decryptedBytes); } } ```

8.2 集成测试脚本

创建测试脚本test_encryption.sh:

``` !/bin/bash echo "开始加密系统测试..." 测试数据库连接加密 curl -X POST http://localhost:8080/api/test/db-connection \ -H "Content-Type: application/json
AI咨询
热线电话

028-85154420

15388110056

全国售前咨询电话

扫码咨询
安答联动微信公众号二维码

微信扫码关注安答联动

申请试用
热线电话
申请试用

安答联动档案管理系统