Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.io.StringReader;
import java.io.StringWriter;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
Expand All @@ -47,6 +48,35 @@ public class XmlUtil {
static {
factory.setValidating(false);
vfactory.setValidating(true);
// XXE(XML External Entity) 취약점 방지
applyXxeProtection(factory, false);
applyXxeProtection(vfactory, true);
}

/**
* XXE(XML External Entity Injection, CWE-611) 취약점을 방지하기 위해
* 외부 엔티티 처리를 제한한다.
*
* 외부 일반/파라미터 엔티티를 차단하면 검증 여부와 무관하게 외부 엔티티를 통한
* 로컬 파일 읽기·SSRF를 막을 수 있다. 스키마 검증(validating=true)이 필요한
* 파서는 DTD 로딩을 유지해야 하므로 외부 엔티티 차단만 적용한다.
*
* @param dbf 보호를 적용할 DocumentBuilderFactory
* @param validating 검증 파서 여부(true면 DTD 로딩을 유지)
*/
private static void applyXxeProtection(DocumentBuilderFactory dbf, boolean validating) {
try {
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
if (!validating) {
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
}
} catch (ParserConfigurationException e) {
// 특정 기능을 지원하지 않는 파서에서도 나머지 방어는 적용되도록 무시한다.
}
}

public static Node getRootNode(String filePath) throws Exception{
Expand Down Expand Up @@ -184,6 +214,7 @@ public static void addNode(Node contextNode, String xPath, String xmlStr) throws
Node parentsNode = componentList.item(0);

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
applyXxeProtection(factory, false);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(xmlStr)));
Node node = doc.getDocumentElement();
Expand All @@ -202,6 +233,7 @@ public static void addNode(Node contextNode, String xPath, String xmlStr, String
Node parentsNode = componentList.item(0);

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
applyXxeProtection(factory, false);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(xmlStr)));
Node node = doc.getDocumentElement();
Expand All @@ -225,6 +257,7 @@ public static void addFirstNode(Node contextNode, String xPath, String xmlStr, S
Node parentsNode = componentList.item(0);

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
applyXxeProtection(factory, false);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(xmlStr)));
Node node = doc.getDocumentElement();
Expand Down
Loading