XXE (XML External Entity) is a fraudulent act that uses the XML external reference function to acquire (leak) the contents of a file inside the server or access a file on the internal network.
Since XXE may be expressed in applications that handle XML, care must be taken when handling XML documents.
To handle XML in Java, consider using javax.xml.parsers.DocumentBuilder. Be done.
Therefore, after that, you can reproduce it using javax.xml.parsers.DocumentBuilder. Let's think about countermeasures.
There is also a way to control the XXE basics link with JavaVM properties, so that may be the quickest way. On the other hand, if you are a Java programmer, it should not be difficult to create and control a resolver yourself.
In the source code program below, the XML file is specified in the first argument and the operation mode of the external reference is specified in the second argument, so the XML file ([C: \ z \ xmlxxe] is the default operation mode. \ in1.xml](https://qiita.com/tomoki0sanaki/items/015b6e8b807ed256a6e4#xml%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB--in1xml)) I will read.
Like this.
In the case of Java, it means that it will be attacked by XXE by default.
Next is [javax.xml.parsers.DocumentBuilder # setEntityResolver () method](https://docs.oracle.com/javase/jp/6/api/javax/xml/parsers/DocumentBuilder.html#setEntityResolver (org.xml) Try giving "NULL" in .sax.EntityResolver)).
Like this.
Unlike the .NET Framework, ** Null is the default resolver object, so in the case of Java, even NULL is subject to XXE attacks. ** **
Next is "** I want to use the external reference function in a limited way, but I want to prevent XXE ". Or, if you say " I want to prevent the external reference function by modifying the resolver **", you can make your own resolver.
That is, [javax.xml.parsers.DocumentBuilder # setEntityResolver () method](https://docs.oracle.com/javase/jp/6/api/javax/xml/parsers/DocumentBuilder.html#setEntityResolver (org.xml) .sax.EntityResolver))) has the first argument "org.xml.sax.EntityResolver Since it is an interface type, create your own class that inherits it and use it [javax.xml.parsers.DocumentBuilder # setEntityResolver () method](https://docs.oracle.com/javase/jp/6/api/ By assigning it to the first argument of javax / xml / parsers / DocumentBuilder.html # setEntityResolver (org.xml.sax.EntityResolver)), you can freely control the external reference.
The method that must be overwritten is "org.xml.sax.InputSource.InputSource resolveEntity (String publicId, String systemId) /EntityResolver.html#resolveEntity (java.lang.String,% 20java.lang.String)) "method only.
The key part of this is the String type that indicates the URL of the external reference in the second argument, so the corresponding "[org.xml.sax.InputSource.InputSource](https://docs.oracle.com/" javase / jp / 6 / api / org / xml / sax / InputSource.html) ”type is just returned.
And the appropriate from this "org.xml.sax.InputSource.InputSource" type "Java.io.InputStream" class or "[java.io.Reader](https:: //docs.oracle.com/javase/jp/6/api/java/io/Reader.html) ”class should be returned.
For example, individual customization is possible, such as requiring authentication or allowing only specific URIs.
The "exEntityResolver class" of the source code "exEntityResolver.java" is finally empty java.io.ByteArrayInputStream for systemId indicating all URIs. I decided to return the "exInputSource" class that only returns jp / 6 / api / java / io / ByteArrayInputStream.html).
It looks like this.
XXEtest.java
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import java.io.File;
import org.xml.sax.EntityResolver;
public class XXEtest{
public static void main(String args[]){
System.out.println("java.exe test <<inFile>> <<Resolver>>");
if(0 < args.length){
Boolean IsResolve = false;
exEntityResolver myExEntityResolver = null;
if(1 < args.length){
if(args[1].equals("null") == true){
IsResolve = true;
}else{
myExEntityResolver = new exEntityResolver();
}
}
try{
DocumentBuilderFactory tempDocumentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder tempDocumentBuilder = tempDocumentBuilderFactory.newDocumentBuilder();
if(IsResolve == true){
tempDocumentBuilder.setEntityResolver(null);
}else if(myExEntityResolver != null){
tempDocumentBuilder.setEntityResolver(myExEntityResolver);
}
Document tempDocument = tempDocumentBuilder.parse(new File(args[0]));
System.out.println("getTextContent : " + tempDocument.getTextContent());
System.out.print("getXmlStandalone: ");
tempDocument.setXmlStandalone(true);
System.out.println(tempDocument.getXmlStandalone());
System.out.println("========Detail=================");
PrintNode(tempDocument.getChildNodes(), "");
}catch(Exception e){
e.printStackTrace();
}
}
}
static void PrintNode(NodeList nodeList, String spacer){
Node node = null;
for(int i=0; i< nodeList.getLength(); i++){
node = nodeList.item(i);
String typeStr = "unknown";
switch(node.getNodeType()){
case Node.ELEMENT_NODE:
typeStr = "ELEMENT_NODE";
break;
case Node.ATTRIBUTE_NODE:
typeStr = "ATTRIBUTE_NODE";
break;
case Node.TEXT_NODE:
typeStr = "TEXT_NODE";
break;
case Node.CDATA_SECTION_NODE:
typeStr = "CDATA_SECTION_NODE";
break;
case Node.ENTITY_REFERENCE_NODE:
typeStr = "ENTITY_REFERENCE_NODE";
break;
case Node.ENTITY_NODE:
typeStr = "ENTITY_NODE";
break;
case Node.PROCESSING_INSTRUCTION_NODE:
typeStr = "PROCESSING_INSTRUCTION_NODE";
break;
case Node.COMMENT_NODE:
typeStr = "COMMENT_NODE";
break;
case Node.DOCUMENT_NODE:
typeStr = "DOCUMENT_NODE";
break;
case Node.DOCUMENT_TYPE_NODE:
typeStr = "DOCUMENT_TYPE_NODE";
break;
case Node.NOTATION_NODE:
typeStr = "NOTATION_NODE";
break;
}
System.out.println(spacer + "name =" + node.getNodeName() + ", type=" + typeStr);
System.out.println(spacer + "value=" + node.getNodeValue());
System.out.println(spacer + "getTextContent=" + node.getTextContent());
if(node.hasChildNodes() == true){
PrintNode(node.getChildNodes(), spacer + " ");
}
}
}
}
A resolver that just returns an InputSource class that just returns an empty ByteArrayInputStream
exEntityResolver.java
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import java.io.IOException;
public class exEntityResolver implements EntityResolver{
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException{
System.out.println("publicId: " + publicId);
System.out.println("systemId: " + systemId);
return (InputSource)new exInputSource();
}
}
An InputSource class that just returns an empty ByteArrayInputStream.
exInputSource.java
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.Reader;
import java.io.InputStreamReader;
public class exInputSource extends InputSource{
ByteArrayInputStream myStream;
public exInputSource(){
byte[] hako = new byte[0];
this.myStream = new ByteArrayInputStream(hako);
}
public InputStream getByteStream(){
return (InputStream)this.myStream;
}
public Reader getCharacterStream(){
return (Reader)new InputStreamReader(this.myStream);
}
}
Recommended Posts