XML文件作为常用的配置文件格式,经常存储数据库连接字符串、接口密钥、系统参数等敏感信息,明文存储会让这些信息直接暴露,一旦文件被非法访问就会引发严重的安全问题。因此掌握XML文件的加密解密方法,做好配置文件的安全防护非常重要。
常见的XML加密方案
对称加密方案
对称加密是使用同一个密钥进行加密和解密,适合对XML配置文件进行整体加密,常见的算法有AES、DES等,其中AES的安全性更高,更推荐使用。这种方案的优势是加密解密速度快,适合频繁读取配置文件的场景。
使用AES算法加密XML文件的示例代码如下:
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class XmlAesEncrypt {
// AES加密方法
public static String encrypt(String content, String key) throws Exception {
Cipher cipher = Cipher.getInstance("AES");
SecretKey secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedBytes = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encryptedBytes);
}
// AES解密方法
public static String decrypt(String encryptedContent, String key) throws Exception {
Cipher cipher = Cipher.getInstance("AES");
SecretKey secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] decodedBytes = Base64.getDecoder().decode(encryptedContent);
byte[] decryptedBytes = cipher.doFinal(decodedBytes);
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
public static void main(String[] args) throws Exception {
// 原始XML内容
String xmlContent = "<?xml version="1.0" encoding="UTF-8"?>n" +
"<config>n" +
" <db_host>127.0.0.1</db_host>n" +
" <db_user>root</db_user>n" +
" <db_password>test123456</db_password>n" +
"</config>";
// 16位AES密钥
String aesKey = "1234567890abcdef";
// 加密XML
String encryptedXml = encrypt(xmlContent, aesKey);
System.out.println("加密后的XML内容:" + encryptedXml);
// 解密XML
String decryptedXml = decrypt(encryptedXml, aesKey);
System.out.println("解密后的XML内容:" + decryptedXml);
}
}
非对称加密方案
非对称加密使用公钥和私钥 pair,公钥用于加密,私钥用于解密,适合需要跨系统传输XML配置文件的场景,常见的算法是RSA。这种方案的安全性更高,但是加密解密速度比对称加密慢,通常用来加密对称加密的密钥,而不是直接加密整个XML文件。
使用RSA加密对称密钥的示例代码如下:
import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class RsaKeyEncrypt {
// 生成RSA密钥对
public static KeyPair generateKeyPair() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
return keyPairGenerator.generateKeyPair();
}
// 公钥加密
public static String encryptByPublicKey(String content, String publicKeyStr) throws Exception {
byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedBytes = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encryptedBytes);
}
// 私钥解密
public static String decryptByPrivateKey(String encryptedContent, String privateKeyStr) throws Exception {
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decodedBytes = Base64.getDecoder().decode(encryptedContent);
byte[] decryptedBytes = cipher.doFinal(decodedBytes);
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
public static void main(String[] args) throws Exception {
// 生成密钥对
KeyPair keyPair = generateKeyPair();
String publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
String privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
// 要加密的AES密钥
String aesKey = "1234567890abcdef";
// 用公钥加密AES密钥
String encryptedAesKey = encryptByPublicKey(aesKey, publicKey);
System.out.println("加密后的AES密钥:" + encryptedAesKey);
// 用私钥解密AES密钥
String decryptedAesKey = decryptByPrivateKey(encryptedAesKey, privateKey);
System.out.println("解密后的AES密钥:" + decryptedAesKey);
}
}
XML配置文件安全保护的其他注意事项
- 密钥不要硬编码在代码里,建议存储在环境变量或者专门的密钥管理服务中,避免密钥随代码泄露。
- 对XML配置文件的访问权限做严格控制,只给需要的服务账号读取权限,禁止普通用户访问。
- 如果XML配置文件需要传输,建议配合HTTPS协议使用,避免传输过程中被窃听。
- 定期对XML配置文件做安全审计,检查是否存在明文存储的敏感信息,及时修复安全隐患。
- 可以对XML中的敏感字段单独加密,而不是加密整个文件,减少解密的性能开销,比如只加密<db_password>这类字段的内容。
不同场景的方案选择
如果是单机部署的应用,只需要本地读取XML配置文件,优先选择AES对称加密方案,实现简单且性能足够。如果是多系统之间传输XML配置文件,建议采用RSA+AES的混合方案,用RSA加密AES密钥,用AES加密XML文件内容,兼顾安全性和性能。如果对安全性要求极高,还可以结合数字签名技术,验证XML文件的完整性,防止文件被篡改。