1. 程式人生 > >通過JAXB看XML外部實體注入(XML External Entity)

通過JAXB看XML外部實體注入(XML External Entity)

我們先使用JAXB提供的註解標記下java類和XML對映關係:

package jaxb;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Student {

	@XmlElement(name = "name")
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Student [name=" + name + "]";
	}

}

下面這個類使用JAXB的API進行物件和xml直接的相互轉換:

package jaxb;

import java.io.FileInputStream;
import java.io.StringReader;
import java.io.StringWriter;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;

public class Main {

	public static void main(String[] args) throws Exception {
		String xml = readContent("src/jaxb/1.xml");
		Object obj = xmlToObjectXXE(xml, Student.class);
		System.out.println(objectToXML(obj, Student.class));
	}

	public static String readContent(String file) throws Exception {
		FileInputStream input = new FileInputStream(file);
		byte[] content = new byte[2 * 1024];
		int realBytes = input.read(content);
		input.close();
		return new String(content, 0, realBytes, "UTF-8");
	}

	public static Object xmlToObjectXXE(String xml, Class<?> klass) throws Exception {
		JAXBContext context = JAXBContext.newInstance(klass);
		Unmarshaller unmarshaller = context.createUnmarshaller();
		return unmarshaller.unmarshal(new StringReader(xml));
	}

	public static Object xmlToObjectSafe(String xml, Class<?> klass) throws Exception {
		JAXBContext context = JAXBContext.newInstance(klass);

		XMLInputFactory xif = XMLInputFactory.newFactory();
		xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
		xif.setProperty(XMLInputFactory.SUPPORT_DTD, true);
		XMLStreamReader xsr = xif.createXMLStreamReader(new StringReader(xml));

		Unmarshaller unmarshaller = context.createUnmarshaller();
		return unmarshaller.unmarshal(xsr);
	}

	public static String objectToXML(Object obj, Class<?> klass) throws Exception {
		JAXBContext jaxbContext = JAXBContext.newInstance(klass);
		Marshaller marshaller = jaxbContext.createMarshaller();

		marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
		marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
		marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);

		StringWriter writer = new StringWriter();
		marshaller.marshal(obj, writer);
		writer.close();

		return writer.toString();
	}
}
xmlToObjectXXE()這個方法解析xml,存在XXE注入;而xmlToObjectSafe是安全的解析方式。

比如我們xml內容是:

<!DOCTYPE student[ 

 <!ENTITY my_outer_entity SYSTEM "file:///c:/demo.txt">  
 
]>

<student>
	<name>&my_outer_entity;</name>
</student>


如果使用xmlToObjectXXE得到的結果是:可以明顯地看到XXE攻擊,讀取了c:/demo.txt的內容


如果使用xmlToObjectSafe解析得到結果是: