生產環境嚴禁在配置文件明文存儲資料庫密碼等敏感資訊。Spring 提供 PropertyPlaceholderConfigurer 擴展點,透過重寫 convertProperty 方法,可在屬性注入前自動解密,實現「配置文件存密文、運行時用明文」的安全目標。
jdbc.password)存儲 AES 加密後的密文EncryptPropertyPlaceholderConfigurer 繼承 PropertyPlaceholderConfigurerconvertProperty(String propertyName, String propertyValue):若屬性名在加密清單中,調用 AES 解密並返回明文;否則返回原值public class EncryptPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
// 需解密的屬性名清單
private String[] encryptPropNames = {"jdbc.username", "jdbc.password"};
// AES 密鑰(16 位或 16 倍數)
private String code = "gzxcxxxtgcyxgs01";
@Override
protected String convertProperty(String propertyName, String propertyValue) {
if (isEncryptProp(propertyName)) {
try {
String decrypted = AESEncryptor.decrypt(code, propertyValue);
return decrypted.isEmpty() ? propertyValue : decrypted;
} catch (Exception e) {
e.printStackTrace();
return propertyValue; // 解密失敗回退原值
}
}
return propertyValue;
}
private boolean isEncryptProp(String name) {
for (String encryptName : encryptPropNames) {
if (encryptName.equals(name)) return true;
}
return false;
}
}
需提供 AESEncryptor.encrypt(key, plaintext) 與 decrypt(key, ciphertext) 靜態方法。密鑰長度必須為 16/24/32 位元組(AES-128/192/256)。
<bean class="com.example.common.web.EncryptPropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="locations">
<list>
<value>classpath*:/application.properties</value>
</list>
</property>
</bean>
替換原有的 <context:property-placeholder>。
// 測試生成密文
String key = "1234567887654321"; // 16 位
String plain = "123456";
String cipher = AESEncryptor.encrypt(key, plain); // 如:N!Kk8dwLm0z7hlGkq2dbdQ==
System.out.println(cipher);
將密文寫入 application.properties:
jdbc.username=admin
jdbc.password=N!Kk8dwLm0z7hlGkq2dbdQ==
EnvironmentPostProcessor 或 PropertySourceLoader 實現同樣效果透過繼承 PropertyPlaceholderConfigurer,以極低侵入性實現配置文件敏感字段加密,是 Spring 專案落地安全合規的常用手段。