在实际业务开发中,XML文件常被用来存储配置信息、数据交换内容,其中可能包含身份证号、手机号、支付密码等敏感数据。如果对整个XML文件进行加密,会导致非敏感数据也无法被正常解析读取,增加不必要的性能开销。因此只加密XML中的特定敏感节点,是实现数据安全与读取效率平衡的最佳方案。

XML特定节点加密的核心思路
XML特定节点加密的本质是定位到需要保护的节点,将其文本内容替换为加密后的密文,同时保留XML的整体结构和其他非敏感节点的内容。整个流程主要分为四个步骤:
- 解析XML文件,获取节点树结构
- 根据规则匹配需要加密的敏感节点
- 使用加密算法对节点文本内容进行加密
- 将加密后的密文替换原节点内容,重新生成XML文件
Java实现XML特定节点加密示例
1. 准备工作
首先需要引入XML解析和加密相关的依赖,这里使用JDK自带的javax.xml.parsers包处理XML,使用javax.crypto包实现AES加密。示例的敏感节点规则为:节点名称为idCard、phone、bankAccount的节点需要进行加密。
2. 加密工具类实现
先实现AES加密和解密的基础工具类,代码如下:
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 AESUtil {
// 生成AES密钥,默认128位
public static String generateKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
SecretKey secretKey = keyGenerator.generateKey();
return Base64.getEncoder().encodeToString(secretKey.getEncoded());
}
// AES加密
public static String encrypt(String content, String key) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.getDecoder().decode(key), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] encryptedBytes = cipher.doFinal(content.getEncoded(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encryptedBytes);
}
// AES解密
public static String decrypt(String encryptedContent, String key) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.getDecoder().decode(key), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedContent));
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
}
3. XML节点加密实现
接下来实现XML特定节点的加密逻辑,代码如下:
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.util.Arrays;
import java.util.List;
public class XmlNodeEncryptor {
// 需要加密的敏感节点名称列表
private static final List<String> SENSITIVE_NODE_NAMES = Arrays.asList("idCard", "phone", "bankAccount");
public static void encryptXmlFile(String inputPath, String outputPath, String encryptKey) throws Exception {
// 解析XML文件
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new File(inputPath));
// 遍历所有节点,匹配敏感节点进行加密
encryptSensitiveNodes(document.getDocumentElement(), encryptKey);
// 将修改后的Document写回文件
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource domSource = new DOMSource(document);
StreamResult streamResult = new StreamResult(new File(outputPath));
transformer.transform(domSource, streamResult);
}
private static void encryptSensitiveNodes(Node node, String encryptKey) throws Exception {
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) node;
// 如果当前节点名称是敏感节点,加密其文本内容
if (SENSITIVE_NODE_NAMES.contains(element.getNodeName())) {
String originalText = element.getTextContent();
if (originalText != null && !originalText.isEmpty()) {
String encryptedText = AESUtil.encrypt(originalText, encryptKey);
element.setTextContent(encryptedText);
}
}
// 递归遍历子节点
NodeList childNodes = element.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
encryptSensitiveNodes(childNodes.item(i), encryptKey);
}
}
}
public static void main(String[] args) {
try {
// 生成加密密钥
String encryptKey = AESUtil.generateKey();
System.out.println("加密密钥:" + encryptKey);
// 执行加密,输入文件和输出文件路径根据实际情况修改
encryptXmlFile("input.xml", "encrypted.xml", encryptKey);
System.out.println("XML敏感节点加密完成");
} catch (Exception e) {
e.printStackTrace();
}
}
}
4. 解密实现
解密是加密的逆过程,遍历加密后的XML文件,匹配敏感节点,将密文解密后替换原内容即可,核心代码如下:
private static void decryptSensitiveNodes(Node node, String encryptKey) throws Exception {
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) node;
if (SENSITIVE_NODE_NAMES.contains(element.getNodeName())) {
String encryptedText = element.getTextContent();
if (encryptedText != null && !encryptedText.isEmpty()) {
String decryptedText = AESUtil.decrypt(encryptedText, encryptKey);
element.setTextContent(decryptedText);
}
}
NodeList childNodes = element.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
decryptSensitiveNodes(childNodes.item(i), encryptKey);
}
}
}
注意事项
- 加密密钥需要妥善管理,建议存储在安全的配置中心或者密钥管理服务中,不要硬编码在代码里
- 敏感节点的匹配规则可以根据业务需求灵活调整,比如支持XPath表达式匹配,满足更复杂的节点选择场景
- 加密后的XML文件如果需要传输,建议同时对密钥进行加密处理,避免密钥泄露导致数据被破解
- 如果XML节点包含子节点结构,而非纯文本内容,需要对整个子节点结构序列化为字符串后再加密,解密后再反序列化还原
XML加密节点加密敏感信息保护XML_security修改时间:2026-06-16 19:27:24