通过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,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解析得到结果是:

相关文章

php输出xml格式字符串
J2ME Mobile 3D入门教程系列文章之一
XML轻松学习手册
XML入门的常见问题(一)
XML入门的常见问题(三)
XML轻松学习手册(2)XML概念