You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Tomcat Web应用中加密/解密敏感属性

替代Jasypt的敏感字段加密方案及GitLab集成实践

一、替代Jasypt的可行方案

鉴于Jasypt维护停滞,推荐以下两种可控性强的方案:

1. 自定义加密工具类

自己实现轻量级对称加密(如AES),完全掌控加密逻辑,无需依赖第三方库。核心思路是:

  • 编写加密工具,对敏感字段加密后写入application.properties(用ENC(xxx)标记加密值)
  • 应用启动时,读取环境变量中的解密密钥,对标记的加密字段进行解密,注入到配置上下文

2. 利用Spring生态原生加密能力(Spring项目专属)

如果是Spring Boot/Spring MVC应用,可通过EnvironmentPostProcessor或自定义PropertySource实现解密,配合Spring Cloud Config的加密功能(若使用配置中心),无需额外引入第三方加密库。

二、GitLab变量集成的具体操作

结合你的环境限制(WAR包部署、systemctl启停、CI+本地部署),分两种场景实现:

1. CI流水线部署

  • 步骤1:存储敏感变量:在GitLab项目的Settings > CI/CD > Variables中添加DB_PASSWORD、API_TOKEN、ENCRYPT_KEY等变量,勾选Protected和Masked防止泄露。
  • 步骤2:部署时注入配置:
    方案A:直接生成明文敏感配置文件(适合无需加密存储配置的场景)
    deploy:
      stage: deploy
      script:
        # 生成生产环境配置文件
        - echo "db.password=${DB_PASSWORD}" > application-prod.properties
        - echo "api.token=${API_TOKEN}" >> application-prod.properties
        # 上传到Tomcat服务器外部配置目录(避免打包进WAR)
        - scp application-prod.properties tomcat-user@your-server:/opt/tomcat/conf/
        # 重启Tomcat
        - ssh tomcat-user@your-server "systemctl restart tomcat"
    
    方案B:加密配置+传递密钥(适合需要加密存储配置的场景)
    在CI脚本中将解密密钥注入Tomcat的环境变量:
    deploy:
      stage: deploy
      script:
        # 写入Tomcat的systemd override配置,添加解密密钥环境变量
        - ssh tomcat-user@your-server "echo 'Environment=\"ENCRYPT_KEY=${ENCRYPT_KEY}\"' > /etc/systemd/system/tomcat.service.d/encrypt-key.conf"
        - ssh tomcat-user@your-server "systemctl daemon-reload"
        # 上传加密后的application-prod.properties到服务器
        - scp src/main/resources/application-prod.properties tomcat-user@your-server:/opt/tomcat/conf/
        - ssh tomcat-user@your-server "systemctl restart tomcat"
    

2. 本地手动部署

  • 避免将敏感字段打包进WAR,在Tomcat的conf目录下创建application-local-prod.properties,写入明文敏感值(仅限本地测试用,注意文件权限)。
  • 若使用加密方案,启动Tomcat前临时设置解密密钥环境变量:
    export ENCRYPT_KEY=your-local-secure-key
    systemctl start tomcat
    
    或者修改Tomcat的systemd配置文件临时添加环境变量,启动后及时移除。

三、Tomcat环境适配要点

  • 外部化配置:将敏感配置放在Tomcat外部目录(如conf/),通过Tomcat的shared.loader配置加载,避免敏感信息打包进WAR。
  • 权限控制:确保服务器上的敏感配置文件权限为600,仅Tomcat用户可读:
    chmod 600 /opt/tomcat/conf/application-prod.properties
    chown tomcat:tomcat /opt/tomcat/conf/application-prod.properties
    
  • 密钥安全:本地部署时密钥通过环境变量传递,不要硬编码;CI部署时用GitLab受保护变量,禁止在日志中输出密钥。

四、自定义AES加密实现示例(Spring项目)

1. 加密工具类

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class AESUtils {
    private static final String ALGORITHM = "AES";

    public static String encrypt(String plainText, String key) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        return Base64.getEncoder().encodeToString(cipher.doFinal(plainText.getBytes()));
    }

    public static String decrypt(String encryptedText, String key) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        return new String(cipher.doFinal(Base64.getDecoder().decode(encryptedText)));
    }
}

2. 配置解密处理器

import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class EncryptedPropertyProcessor {
    private final Environment environment;

    public EncryptedPropertyProcessor(Environment environment) {
        this.environment = environment;
    }

    @PostConstruct
    public void processEncryptedProperties() {
        if (!(environment instanceof StandardEnvironment standardEnv)) {
            return;
        }

        String encryptKey = System.getenv("ENCRYPT_KEY");
        if (encryptKey == null) {
            throw new IllegalStateException("ENCRYPT_KEY environment variable is required for decryption");
        }

        Map<String, Object> decryptedProps = new HashMap<>();
        // 处理数据库密码
        processEncryptedField("db.password", encryptKey, decryptedProps);
        // 处理API令牌
        processEncryptedField("api.token", encryptKey, decryptedProps);

        // 将解密后的配置加入到环境变量最前面,优先读取
        standardEnv.getPropertySources().addFirst(new PropertySource<>("decryptedProperties") {
            @Override
            public Object getProperty(String name) {
                return decryptedProps.get(name);
            }
        });
    }

    private void processEncryptedField(String propertyName, String key, Map<String, Object> decryptedProps) {
        String encryptedValue = environment.getProperty(propertyName);
        if (encryptedValue == null || !encryptedValue.startsWith("ENC(") || !encryptedValue.endsWith(")")) {
            return;
        }

        try {
            String plainValue = AESUtils.decrypt(encryptedValue.substring(4, encryptedValue.length() - 1), key);
            decryptedProps.put(propertyName, plainValue);
        } catch (Exception e) {
            throw new RuntimeException("Failed to decrypt property: " + propertyName, e);
        }
    }
}

3. 加密后的配置示例

在application-prod.properties中写入:

db.password=ENC(your-encrypted-db-password)
api.token=ENC(your-encrypted-api-token)

内容的提问来源于stack exchange,提问作者pbuchheit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 11:27:15