要求:当我向我的应用程序传递以下请求时,
1)如何对这种有风险的输入XML进行xml验证。
2)如何在libxml2中禁用XXE,即不解析实体字段
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY foo SYSTEM "file:///etc/issue">
]><TRANSACTION>
<FUNCTION_TYPE>LINE_ITEM</FUNCTION_TYPE>
<COMMAND>ADD</COMMAND>
<COUNTER>3</COUNTER>
<MAC>qof2EtycqT9YMcmOfKowpyXVbRpgM/7rncS3liK4JOs=</MAC>
<MAC_LABEL>P_206</MAC_LABEL>
<RUNNING_TAX_AMOUNT>0.00</RUNNING_TAX_AMOUNT>
<RUNNING_TRANS_AMOUNT>1.00</RUNNING_TRANS_AMOUNT>
<LINE_ITEMS>
<MERCHANDISE>
<LINE_ITEM_ID>1</LINE_ITEM_ID>
<DESCRIPTION>&foo;</DESCRIPTION>
<QUANTITY>1</QUANTITY>
<UNIT_PRICE>5.00</UNIT_PRICE>
<EXTENDED_PRICE>5.00</EXTENDED_PRICE>
</MERCHANDISE>
</LINE_ITEMS>
</TRANSACTION>
据我所知,从libxml2版本2.9开始,默认情况下XXE已被禁用。但我们目前使用的是2.7.7版本。
根据这个链接正在处理中
Enum xmlParserOption不应该在libxml2中定义以下选项:
XML_PARSE_NOENT:展开实体并用替换文本XML_PARSE_DTDLOAD替换它们:加载外部DTD
到目前为止,我还在使用xmlParseMemory
函数来解析内存块并构建一棵树。此函数不接受任何参数来设置xmlParserOption。
然后改为xmlReadMemory
函数,它与xmlParseMemory
函数做同样的事情,但参数不同。
docPtr = xmlReadMemory(szXMLMsg, iLen, "noname.xml", NULL, XML_PARSE_RECOVER);
我仍然观察到实体字段正在被解析。有人能帮我吗?如果您需要更多的信息,请告诉我。
谢谢您抽时间见我。
问候
普拉文
发布于 2014-04-08 14:48:18
如果不指定XML_PARSE_NOENT
,则仍将解析ENTITY
声明,但不会替换该实体。另外,文件/etc/issue
也不会被打开,您可以用strace
进行验证。因此,为了免受XXE的影响,您只需不传递XML_PARSE_NOENT
解析器选项。
选项的名称有点误导,XML_PARSE_NOENT
意味着不应该在解析的文档中创建实体节点。因此,每个实体都扩大了。更好的名字应该是类似于XML_PARSE_EXPAND_ENTITIES
的名字。
如果您确实希望确保或希望扩展实体,对要加载的URL进行细粒度控制,则可以使用xmlSetExternalEntityLoader
安装自己的外部实体加载器。如果您的处理程序总是返回NULL,那么您将处于安全的一方。但是请注意,外部实体加载器用于加载所有类型的外部资源,因此完全禁用它可能会破坏其他内容(例如,XIncludes或XSLT样式表)。
编辑:我不知道在您的情况下为什么要替换这个实体。下面是一个测试程序:
#include <stdio.h>
#include <stdlib.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
static xmlNodePtr
find_node(xmlNodePtr parent, const char *name) {
for (xmlNodePtr cur = parent->children; cur != NULL; cur = cur->next) {
if (cur->type == XML_ELEMENT_NODE
&& xmlStrcmp(cur->name, (const xmlChar*)name) == 0
) {
return cur;
}
}
fprintf(stderr, "Element '%s' not found\n", name);
abort();
return NULL;
}
int
main(int argc, char **argv) {
static const char buf[] =
"<?xml version=\"1.0\"?>\n"
"<!DOCTYPE foo [\n"
"<!ENTITY foo SYSTEM \"file:///etc/issue\">\n"
"]><TRANSACTION>\n"
"<FUNCTION_TYPE>LINE_ITEM</FUNCTION_TYPE>\n"
"<COMMAND>ADD</COMMAND>\n"
"<COUNTER>3</COUNTER>\n"
"<MAC>qof2EtycqT9YMcmOfKowpyXVbRpgM/7rncS3liK4JOs=</MAC>\n"
"<MAC_LABEL>P_206</MAC_LABEL>\n"
"<RUNNING_TAX_AMOUNT>0.00</RUNNING_TAX_AMOUNT>\n"
"<RUNNING_TRANS_AMOUNT>1.00</RUNNING_TRANS_AMOUNT>\n"
"<LINE_ITEMS>\n"
"<MERCHANDISE>\n"
"<LINE_ITEM_ID>1</LINE_ITEM_ID>\n"
"<DESCRIPTION>&foo;</DESCRIPTION>\n"
"<QUANTITY>1</QUANTITY>\n"
"<UNIT_PRICE>5.00</UNIT_PRICE>\n"
"<EXTENDED_PRICE>5.00</EXTENDED_PRICE>\n"
"</MERCHANDISE>\n"
"</LINE_ITEMS>\n"
"</TRANSACTION>\n";
xmlDocPtr doc = xmlReadMemory(buf, sizeof(buf), "noname.xml", NULL,
XML_PARSE_RECOVER);
xmlNodePtr trans = find_node((xmlNodePtr)doc, "TRANSACTION");
xmlNodePtr items = find_node(trans, "LINE_ITEMS");
xmlNodePtr merch = find_node(items, "MERCHANDISE");
xmlNodePtr desc = find_node(merch, "DESCRIPTION");
for (xmlNodePtr cur = desc->children; cur != NULL; cur = cur->next) {
if (cur->type == XML_ENTITY_REF_NODE) {
printf("entity ref node\n");
}
else {
printf("other node of type: %d\n", cur->type);
}
}
xmlFreeDoc(doc);
return 0;
}
如果我用
gcc -std=c99 -O2 -I/usr/include/libxml2 so.c -lxml2 -o so
然后运行它,结果是
entity ref node
https://stackoverflow.com/questions/22930043
复制相似问题