2014-04-08 8 views
3

요구 사항 : 내가 위험이 같은 입력 XML을 XML 유효성 검사를 수행하는 방법에libxml2in C에서 XXE를 비활성화하는 방법은 무엇입니까?

1) 내 응용 프로그램에 다음과 같은 요청을 전달하면

2) ENTITY을 구문 분석하지 않아야 libxml2를의 예에 결선도를 해제하는 방법 field

<?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

열거 xmlParserOption는 libxml2를 정의 다음과 같은 옵션이 안 : 엔티티를 확장하고 대체 텍스트 XML_PARSE_DTDLOAD로 대체 :

XML_PARSE_NOENT를 외부 DTD를로드

지금까지함수를 사용하여 XML 인 메모리 블록을 구문 분석하고 트리를 작성했습니다. 이 함수는 xmlParserOption을 설정하는 매개 변수를 사용하지 않습니다.

나는 xmlParseMemory 기능과 동일하지만 다른 매개 변수를 취하는 xmlReadMemory 기능으로 변경되었습니다.

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

여전히 ENTITY 필드가 파싱 중입니다. 누구도 도와 줄 수 있습니까? 추가 정보가 필요하면 알려주십시오.

감사합니다. 당신이하지이 XML_PARSE_NOENT를 지정 할 경우

감사

프라 빈

답변

2

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 
+0

안녕은, 당신의 도움을 주셔서 감사합니다. 심지어 엔티티가 교체되지 않기를 원했습니다. xmlReadMemory 함수에서 xmlparseoption으로 XML_PARSE_NOENT 옵션을 지정하지 않았습니다. 위의 함수 호출을 붙여 넣었습니다. 아직도 엔티티가 교체되고 있음을 관찰합니다. 즉, 설명 필드가 // etc/issue 파일의 내용으로 대체되고 있음을 피하려는 시스템에 있습니다. 나는 여기에서 무엇인가 놓치고 있냐?? –

+0

@PraveenPVS 업데이트 된 응답에서 테스트 프로그램을 실행하면 엔티티가 교체되지 않습니다. – nwellnhof

+0

외부 참조가있는 노드를 식별하는 데 도움이되는 노드 유형을 확인해 주셔서 감사합니다. –