본문 바로가기
정보보안(웹해킹)/XXE(XML External Entity) Vulnerability

XML(EXtensible Markup Language)

by 끊임없는정진 2022. 12. 25.

▶XML이란?

XML은 EXtensible Markup Language 의 약자이며, 1998년에 W3C 표준 권고안에 포함되었다. XML은 HTML과 매우 비슷한 문자 기반의 마크업 언어(text-based markup language)이다. 해당 언어는 사람과 기계가 동시에 읽기 편한 구조로 되어 있다. 그러나 XML은 HTML과 같이 데이터를 보여주는 목적이 아닌, 데이터를 저장하고 전달할 목적으로 만들어졌다. 또한, HTML과 달리 태그가 미리 정의되어 있지 않고, 사용자가 직접 정의할 수 있다. 

XML은 서로 다른 시스템끼리 다양한 종류의 데이터를 손쉽게 교환할 수 있도록 해주며, 새로운 태그를 추가해도 계속해서 동작함에 따라 확장성이 좋다. 또한, HTML과 달리 데이터를 전달하고 저장하는 것만을 목적으로 한다. XML은 텍스트 데이터 형식의 언어로 모든 XML 문서는 유니코드 문자로만 이루어진다. 

XML을 기반으로 하는 대표적인 언어로 XHTML, SVG, RDF, RSS, Atom, MathML이 있다.

XML문서는 HTML 문서와 마찬가지로 트리(tree) 형태의 계층구조를 가진다. 이러한 XML 트리는 하나뿐인 루트(root)요소부터 시작하여, 각각의 자식(child)요소에 차례대로 연결된다. XML 트리 구조에 포함되는 모든 요소는 자신만의 자식(child)요소를 가질 수 있다. 부모(parent) 요소는 여러개의 자식(child) 요소를 가질 수 있다. 하지만, 자식(child) 요소는 단 하나의 부모(parent) 요소만을 가진다. 

※ XML은 문서용 마크업 언어를 정의하기 위한 메타언어인 SGML(Standard Generalized Markup Language)을 기반으로 만들어졌다. 

 

▶XML 기본 문법

XML 문서는 맨 첫 줄에 <xml>태그를 사용하여 XML 문서임을 명시해야 한다. 이것을 XML 프롤로그(prolog)라고 하며, 이때 사용되는 <xml>태그의 이름은 소문자 xml로만 사용해야 한다. XML프롤로그의 문법은 아래와 같다. version 속성은 XML 문서에 사용된 XML의 버전, encoding 속성에는 XML 문서의 문자셋(character set)을 명시하며, 기본값은 UTF-8로 설정된다. standalone 속성은 XML 문서가 외부 DTD(Document Type Definition)와 같은 외부 소스의 데이터에 의존하고 있는 문서인지 아닌지를 XML 파서(.parser)에 알려주는 역할을 한다. 해당 속성의 기본값은 no이며, yes로 설정하면 이 문서를 파싱(parsing)할 때 참조해야 할 외부 소스가 없다는 것을 의미한다. 

<?xml version="XML문서버전" encoding="문자셋" standalone="yes|no"?>

 

XML의 문서는 다음과 같은 문법을 따르게 된다.

[1] 모든 XML 요소는 종료 태그를 가져야 한다: HTML에서는 종료 태그를 생략하거나, 빈 태그를 사용해도 대부분의 경우 문제없이 동작한다. 하지만 XML에서는 XHTML과 마찬가지로 종료 태그가 생략되면 오류가 발생한다. 또한, 빈 태그에도 반드시 슬래시(/)를 추가해야만 오류가 발생하지 않는다.

HTML : <h1>XML
       <hr>
XML  : <h1>XML</h1>
       <hr />

[2] XML 태그는 대소문자를 구분한다: HTML에서는 대소문자를 구분하지 않는다. 하지만 XML에서는 태그 이름에 대소문자를 구분하므로, 대소문자가 다르면 다른 요소로 인식한다.

[3] XML에서는 시작 태그와 종료 태그가 모두 대소문자까지 같아야 한다.

<lecture>이 요소는 lecture 요소입니다.</lecture>
<Lecture>이 구문은 오류를 발생합니다.</lecture>

[4] XML 태그의 여닫는 순서는 반드시 지켜져야 한다: 먼저 열린 태그는 그안의 모든 태그가 닫힌 후에야 닫힐 수 있다.

<p><strong>이 구문은 오류를 발생합니다.</p></strong>
<p><strong>이 구문이 정확한 순서입니다.</strong></p>

[5] 속성값은 반드시 따옴표로 감싸야 한다: HTML에서는 속성값을 따옴표로 감싸지 않아도 큰 문제없이 동작한다. 하지만 XML에서는 속성값을 따옴표로 감싸지 않으면 오류가 발생한다.(ex. <student name="이순신"> )

[6] XML에서는 띄어쓰기를 인식한다: HTML에서는 띄어쓰기를 따로 인식하지 않는다. 하지만 XML에서는 여러 번의 띄어쓰기를 그대로 인식한다.

코드 : <p>띄   어 쓰    기</p>
HTML : 띄어쓰기
XML  : 띄   어 쓰    기

 

XML에서는 예약되어 있는 다섯 개의 특별한 기호가 있다. 이 기호를 XML 문서에서 사용하면 XML 파서(해석하는 기계)는 그것을 전혀 다른 의미로 해석한다. 이렇게 기존에 사용하던 의미 그대로 사용하기 위해서 만든 문자셋을 엔티티(Entity)라고 한다. HTML에서는 수많은 문자와 기호를 엔티티로 미리 정의해놓고 사용하는 반면, XML에서 제공하는 엔티티(Entity)는 5개 뿐이다.

기호 엔티티 이름 16진수 엔티티 설명
< &lt; &#60; 보다 작은
> &gt; &#62; 보다 큰
& &amp; &#38; and 기호
" &quot; &#34; 큰따옴표
' &apos; &#39; 작은따옴표

 

그런데 만약, 서로 다른 XML 문서를 통합하려 할 때, 같은 이름을 가진 요소로 인해 충돌이 발생하면 어떻게 할까? 예를 들면, HTML의 body태그와 XML이 body태그를 정의했을 때와 같이 말이다. 이를 막기 위해서 XML 네임스페이스의 선언이 필요하다. XML에서는 접두사(prefix)를 이용하여 위와 같은 이름의 충돌을 방지하고 있다. 서로 같은 이름에 요소마다 서로 다른 접두사를 붙이면 이름의 충돌을 방지할 수 있게 된다. XML에서 이러한 접두사를 사용하려면, 반드시 먼저 접두사에 대한 네임스페이스를 선언해야 한다. XML에서 네임스페이스를 선언하는 문법은 다음과 같다.

<요소이름 xmlns:prefix="URI">

XML 네임스페이스의 선언은 xmlns나 xmlns:로 시작한다. prefix 속성값에서는 이름 앞에 붙게 되는 네임스페이스 접두사(namespace prefix)를 명시한다. 선언하면 해당 요소의 자식(child) 요소에도 같은 네임스페이스가 선언된다. 선언하는 위치는 root든 다른 태그든 상관없다. 예를 들면 다음과 같다.

<!-- body 태그에서 네임스페이스 선언 -->
<root>

    <a:body xmlns:a="https://www.w3.org/TR/html5/">
        <a:h1>html에서의 제목</a:h1>
        <a:p>html에서의 단락</a:p>
    </a:body>
    <b:body xmlns:b="http://codingsam.com/xml/physical/">
        <b:arm>70</b:arm>
        <b:leg>110</b:leg>
    </b:body>
</root>

<!-- root에서 네임스페이스 선언 -->
<root
    xmlns:a="https://www.w3.org/TR/html5/"
    xmlns:b="http://codingsam.com/xml/physical/">
    <a:body>
        <a:h1>html에서의 제목</a:h1>
        <a:p>html에서의 단락</a:p>
    </a:body>
    <b:body>
        <b:arm>70</b:arm>
        <b:leg>110</b:leg>
    </b:body>
</root>

URI란 통합 자원 식별자를 의미하며, 인터넷에 있는 자원을 나타내는 유일한 주소를 의미한다. URI의 존재는 인터넷에서 요구되는 기본조건으로서 인터넷 프로토콜에도 항상 명시된다. 대표적인 예시로 인터넷 도메일 주소를 나타내는 URL(Uniform Resource Locator)이 있다.

 

▶DTD(Document Type Definition)

문서 타입 정의(DTD)는 XML 문서의 구조 및 해당 문서에서 사용할 수 있는 적법한 요소와 속성을 정의한다. DTD는 엔티티를 정의할 수 있으며, 빠른 개발을 위한 내부 DTD를 사용할 수 있다. DTD는 예전부터 사용해 온 구식 방법이지만, 특유의 장점을 바탕으로 아직도 널리 사용되고 있다. 이러한 DTD는 XML문서 내부에 명시할 수 있지만, 별도의 파일로 분리할 수도 있다. DTD를 사용해서 새로운 XML 문서의 구조를 정의해서 새로운 문서 타입을 만들 수 있다. 이렇게 생성되 ㄴDTD는 새로운 문서 타입을 이용한 데이터의 교환에서 표준으로 활용된다. 또한, 응용 프로그램은 DTD의 정의에 따라 XML 문서의 구문 및 구조에 대한 유효성을 검사할 수 있다. 

DTD의 문법은 다음과 같이 시작한다. 

<!DOCTYPE 루트요소 DTD식별자 [ 선언1 선언2 ... ]>

DTD는 <!DOCTYPE으로 시작한다. 루트(root) 요소는 XML 파서(parser)에 명시된 루트 요소부터 파싱(parsing)을 시작하라고 알려주는 역할을 한다. DTD식별자는 프로그램 외부에 존재하는 DTD 파일을 위한 식별자이다. 만약에 DTD 식별자가 외부 주소를 가리키고 있으면, 그것을 외부 서브셋(subset)이라고 한다. 괄호[] 안에는 내부 서브셋(subset)이라 불리는 추가로 선언한 엔티티(entity)의 리스트가 존재한다. 

DTD가 파일 내부에서 선언된다면 해당 선언은 반드시 <!DOCTYPE>안에 위치해야 한다. root요소가 food이고 food의 요소로 name, type,cost의 세 요소를 반드시 포함해야 한다는 사실을 명시하면 다음과 같은 XML을 만들 수 있다(!ELEMENT name,type,cost는 해당 요소들이 #PCDATA 타입의 요소라는 사실을 명시한다.).

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE food [
<!ELEMENT food (name,type,cost)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT type (#PCDATA)>
<!ELEMENT cost (#PCDATA)>
]>
<food>
    <name>상추</name>
    <type>야채</type>
    <cost>2000</cost>
</food>

 

DTD가 XML 파일의 외부에서 선언된다면, <!DOCTYPE>는 반드시 외부 DTD 파일의 주소 정보를 포함해야 한다. 이러한 외부 DTD파일은 .dtd 확장자를 사용하여 저장한다. 

data.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE food SYSTEM "food.dtd">
<food>
    <name>상추</name>
    <type>야채</type>
    <cost>2000</cost>
</food>
food.dtd

<!ELEMENT food (name,type,cost)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT type (#PCDATA)>
<!ELEMENT cost (#PCDATA)>

 

DTD에서는 모든 XML 문서가 다음과 같은 구성 요소로 이루어져 있다고 본다.

[1] 요소(elements)

DTD에서 요소(element)란 XML 문서를 구성하는 가장 중요한 구성요소이다. DTD에서 요소는 다음과 같이 ELEMENT 구문으로 선언할 수 있다.

양식

<!ELEMENT 요소이름 요소카테고리>

또는
<!ELEMENT 요소이름 (요소내용)>

요소 선언 정리 

빈 요소 선언 : <!ELEMENT 요소이름 EMPTY>
하나의 자식 요소만을 가지는 요소의 선언 : <!ELEMENT 요소이름 (자식요소이름)>
여러 자식 요소를 가지는 요소의 선언 : <!ELEMENT 요소이름 (자식1, 자식2, ...)>
최소한 하나 이상의 자식 요소를 가지는 요소의 선언 : <!ELEMENT 요소이름 (자식요소이름+)>
자식 요소를 가질 수도 있고, 가지지 않을 수도 있는 요소의 선언: <!ELEMENT 요소이름 (자식요소이름*)>
자식 요소를 가지지 않거나, 단 하나의 자식 요소만을 가지는 요소의 선언 : <!ELEMENT 요소이름 (자식요소이름?)>
자식 요소를 선택적으로 가지는 요소의 선언 : <!ELEMENT 요소이름 (자식요소이름1,...(자식요소이름2|자식요소이름3|...))>

 

[2] 속성(attributes)

DTD에서 속성은 요소에 대한 추가적인 정보를 제공하며, 해당 요소의 특징을 정의한다. DTD에서 속성은 다음과 같이 ATTLIST 구문으로 선언할 수 있다.

양식

<!ATTLIST 요소이름 속성이름 속성타입 속성값>

예시

<!ELEMENT math EMPTY>
<!ATTLIST math grade CDATA 'F'>

 

속성 타입

속성 타입 설명
CDATA 이 타입의 속성값은 문자 데이터(character data)임.
(속성값1|속성값2|...) 이 타입의 속성값은 나열된 리스트 중 하나에 해당함.
ID 이 타입의 속성값은 하나뿐인 아이디(id)임.
IDREF 이 타입의 속성값은 다른 요소의 아이디(id)임
IDREFS 이 타입의 속성값은 다른 아이디(id)의 리스트임.
NMTOKEN 이 타입의 속성값은 유효한(valid) XML 이름임.
NMTOKENS 이 타입의 속성값은 유효한(valid) XML 이름의 리스트임.
ENTITY 이 타입의 속성값은 엔티티(entity)임.
ENTITIES 이 타입의 속성값은 엔티티(entity)의 리스트임.
NOTATION 이 타입의 속성값은 notation의 이름임.
xml: 이 타입의 속성값은 미리 정의된 예약어인 'xml'임.

 

속성값 

속성값 설명
이 속성의 속성값이 명시되지 않을 경우 사용할 기본값임.
#REQUIRED 이 속성은 반드시 명시되어야 함.
#IMPLIED 이 속성은 명시되어도 되고, 명시되지 않아도 됨.
#FIXED 값 이 속성의 속성값은 명시된 값으로 고정됨.

 

[3] 엔티티(entities)

XML에서는 예약되어 있는 다섯 개의 특별한 기호인 엔티티(entity)가 있다. 이렇게 예약된 기호를 기존에 사용하던 의미 그대로 사용하기 위해서 만든 문자셋을 엔티티(entity)라고 한다. 위와 같은 다섯 개의 엔티티를 제외한 모든 엔티티는 반드시 사용하기 전에 DTD에서 선언해야 한다. 내부 엔티티와 외부 엔티티는 각각 다음과 같이 선언할 수 있다.

양식

내부 엔티티
<!ENTITY 엔티티이름 "엔티티값">
외부 엔티티
<!ENTITY 엔티티이름 SYSTEM "URI또는URL">

예제

내부 엔티티 선언과 사용
<!ENTITY css "Cascading Style Sheets">
<lecture>&css;</lecture> // <lecture>Cascading Style Sheets<lecture>
외부 엔티티 선언과 사용
<!ENTITY html SYSTEM "http://codingsam.com/xml/html.dtd">
<lecture>&html;</lecture> // <lecture>HyperText Markup Language<lecture>
파라미터 엔티티의 선언 (DTD 문서에서만 사용하기 위한 엔티티 : % 기호 들어가는 것을 제외하면 일반 엔티티와 똑같이 사용)
<!ENTITY %엔티티이름 "엔티티값">

 

[4] PCDATA (Parsed Character DATA)

XML 파서에 의해 분석될 문자 데이터를 의미한다. 간단히 말해 XML 요소의 시작 태그와 종료 태그 사이에 위치한 텍스트를 PCDATA라고 생각하면 된다. PCDATA는 XML 파서가 엔티티(entity)와 마크업(markup)으로 나누어서 분석한다. 이렇게 XML 파서에 의해 분석될 문자 데이터만을 가지는 요소는 요소의 내용을 #PCDATA로 명시하여 선언한다(위 DTD예시 참조).

 

[5] CDATA(Character DATA)

XML 파서가 분석하지 않는 문자 데이터를 의미한다. DTD에서 요소의 콘텐츠에는 PCDATA만이 올 수 있으며, 속성의 속성값으로는 CDATA만이 올 수 있다. 

<!ATTLIST 요소이름 속성이름 CDATA 속성값>

 

 

출처 : http://www.tcpschool.com/xml/

댓글