Как отключить XXE в libxml2in C?

Требование: когда я передаю следующий запрос к моей заявке,

1) Как сделать проверку XML на такой входной XML, который является риском

2) Как отключить XXE в libxml2, т.е. не следует разбирать поле ENTITY

<?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 в настоящее время.

По этой ссылке XML_ENTITY_PROCESSING

Enum xmlParserOption не должен иметь следующие параметры, определенные в libxml2:

XML_PARSE_NOENT: расширяет сущности и заменяет их текстом замены XML_PARSE_DTDLOAD: загружает внешнее DTD

До сих пор я использовал xmlParseMemory функция для анализа блока XML в памяти и построения дерева. Эта функция не принимает никаких параметров для установки xmlParserOption.

Затем я изменил на xmlReadMemory функция, которая также делает то же самое, что и xmlParseMemory функция, но принимает разные параметры.

docPtr = xmlReadMemory(szXMLMsg, iLen, "noname.xml", NULL, XML_PARSE_RECOVER);

Тем не менее я наблюдаю, что поле ENTITY разбирается. Кто-нибудь может мне помочь? Пожалуйста, дайте мне знать, если вам нужна дополнительная информация.

Спасибо за ваше время.

С уважением

Praveen

1 ответ

Если вы не укажете XML_PARSE_NOENT, ENTITY объявление все еще анализируется, но объект не будет заменен. Также файл /etc/issue не будет открыт, который вы можете проверить с помощью strace, Таким образом, чтобы защитить от XXE, вы просто не проходите XML_PARSE_NOENT опция парсера.

Название опции немного вводит в заблуждение, XML_PARSE_NOENT означает, что никакие узлы сущности не должны быть созданы в разобранном документе. Следовательно, каждая сущность расширяется. Лучшее имя будет что-то вроде XML_PARSE_EXPAND_ENTITIES,

Если вы действительно хотите убедиться или хотите расширить сущности с детальным контролем над тем, какие URL загружать, вы можете установить свой собственный внешний загрузчик сущностей, используя xmlSetExternalEntityLoader, Если ваш обработчик всегда возвращает NULL, вы в безопасности. Но обратите внимание, что внешний загрузчик сущностей используется для загрузки всех видов внешних ресурсов, поэтому его полное отключение может привести к поломке других вещей (например, таблиц стилей XInclude или 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
Другие вопросы по тегам