*
MSDN*
Bing 제공
|개발자 센터
MSDN 홈 > MSDN 칼럼 > Extreme XML > Microsoft .NET의 보안 XSL 변환

Microsoft .NET의 보안 XSL 변환

Prajakta Joshi
Microsoft Corporation

2003년 7월 28일

요약: 객원 작가인 Prajakta Joshi는 .NET XslTransform 클래스로 XML 데이터를 변환하는 동안 안전하게 프로그래밍하는 방법에 대해 살펴보려고 합니다. 주로 가져온/포함된 스타일시트, document() 함수 참조 확인, 스타일시트 스크립트 사용, 확장 개체 등에 대한 내용을 다룹니다.

참고   이 기사의 모든 내용과 코드 샘플은 .NET Framework 1.1 SDK 의 XslTransform 구현을 참조합니다.

XSLT의 보안 위험

XSLT 1.0 XPath 1.0 과 동일한 데이터 모델에서 작동합니다. XSLT 변환에서는 소스 트리를 결과 트리로 변환하는 규칙을 설명합니다. 해당 언어는 템플릿 규칙, 재귀, 조건부 처리 등과 같은 강력한 구문을 많이 제공합니다.

핵심 언어에는 import/include/document와 같이 프로세서에서 URI 참조를 확인해야 하는 기능이 있습니다. 이것이 이 기사에서 살펴볼 보안 위험의 첫째 범주입니다.

둘째 범주는 XSLT 확장 사용에 대한 내용입니다. XPath 1.0과 마찬가지로 XSLT를 사용하여 데이터를 강력하게 조작할 때는 확장 요소와 함수를 사용해야 합니다. W3C XSLT 1.0 권장 사항을 사용하면 프로세서에서 이런 확장 을 지원할 수 있습니다. 가장 많이 사용하는 확장 메커니즘은 스타일시트 스크립트 블록과 확장 개체입니다. 그러한 확장을 사용하면 XSLT 프로세서가 사용자 대신 코드를 실행할 수 있습니다.

스타일시트, 스크립트 및 안전

언뜻 보면 XSLT 1.0은 XML 문서를 다른 XML 문서로 변환할 수 있는 안전한 언어로 생각됩니다. 또한 일부 사용자는 스타일시트에서 스크립트 블록이나 확장 개체를 사용하지 않으면 안전하다고 생각하기도 합니다.

이런 경우 다음 두 가지 시나리오를 고려해 보십시오.

  • XSLT 응용 프로그램이 신뢰할 수 없는 출처의 스타일시트를 허용하는 서버를 완전히 신뢰하면서 실행될 경우 악의적인 스타일시트가 무한 루프를 실행하고 시스템 리소스를 모두 사용하여 DOS 유형의 침해가 발생할 수 있습니다.
  • 원본 XML과 스타일시트 외에도 XSLT 프로세서는 가져온 스타일시트 , 포함된 스타일시트  또는 document()  함수에서 참조하는 다른 XML 파일 등 그 밖의 리소스에 액세스해야 합니다. 이런 리소스에 액세스하려면 교차 영역 또는 교차 도메인에 액세스할 수 있는 사용 권한이 필요할 수 있습니다.

이 기사에서는 XslTransform 클래스로 XSL 변환을 안전하게 작성할 수 있는 방법을 검토합니다. 이제 외부 리소스 확인과 관련된 보안 문제를 살펴보겠습니다.

외부 리소스 확인

복잡한 처리 논리가 있는 대량의 단일 스타일시트는 비모듈 방식의 단일 프로그램(크기: 1000줄)처럼 유지 관리하기 어렵습니다. 또한 비즈니스 고유의 문제로 인해 다른 모듈에 대해 서로 다른 스타일시트를 작성하는 것이 더 합리적인 경우도 있습니다. XSLT 1.0은 스타일시트 결합을 위한 두 가지 메커니즘 을 제공합니다.

  • Include
  • Import

xsl:include xsl:import  요소에는 모두 포함할/가져올 스타일시트를 식별하는 URI 참조를 값으로 갖는 href 특성이 있습니다. XslTransformXmlResolver를 사용하여 이러한 상대/절대 URI 참조를 확인합니다.

document() 함수는 변환 중 주 소스 문서 외의 다른 XML 문서에 액세스하는 데 사용됩니다. import/include와 document() 확인의 기본적인 차이점은 확인하는 시점입니다. 전자는 XslTransform.Load()  메서드를 사용하여 스타일시트를 컴파일할 때 확인되지만 후자는 XslTransform.Transform()  메서드를 사용하여 스타일시트 변환을 실행할 때 확인됩니다.

XmlResolver의 역할

XML, 가져온/포함된 스타일시트, 외부 엔터티, DTD 또는 스키마가 될 수 있는 외부 URI 참조를 확인할 때 System.Xml API에서 XmlResolver  클래스를 사용합니다. XmlResolverCredentials  속성을 ICredential  개체로 설정할 수 있습니다. 이 클래스에 GetEntity() 메서드를 사용하면 실제로 원본으로 사용하는 개체가 Stream으로 반환됩니다.

XslTransform은 다음 두 경우에 XmlResolver를 사용합니다.

XslTransform 클래스는 XslTransform.Load() 를 호출할 때 포함된/가져온 스타일시트를 사용하여 주 스타일시트를 만듭니다. 확인자 매개 변수가 없는 XslTransform.Load() 가 오버로드된 경우 자격 증명이 없는 기본 XmlUrlResolver XslTransform에 의해 사용자용으로 만들어집니다.

(XmlUrlResolverXmlResolver의 구현이며 System.Xml 네임스페이스의 모든 클래스에 대한 기본 확인자입니다.)

시나리오 1: Import/Include 확인

서버 쪽 응용 프로그램에서 http://www.example.com과 같이 신뢰할 수 있는 파트너 사이트의 스타일시트를 받아들여서 변환을 실행하는 시나리오를 검토하십시오. 신뢰할 수 있는 스타일시트에서 신뢰할 수 없는 다른 웹 사이트의 bad.xsl을 가져오면 어떻게 될까요?

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:include href="http://www.badexample.com/bad.xsl">
<xsl:template match="/">
   ...
</xsl:template>
</xsl:stylesheet>

시나리오 1의 해결 방법: XmlSecureResolver

XmlUrlResolver를 사용하여 시나리오 1을 안전하게 만들 수 있을까요? 그렇지 않습니다. 신뢰할 수 있는 사이트의 URI만 확인하기 위한 웹 사용 권한 집합을 지정할 수 있는 기능이 필요합니다. 이 기능은 .NET Framework SDK 버전 1.1에 처음 소개된 XmlSecureResolver  클래스를 사용하여 수행할 수 있습니다.

XmlSecureResolver 클래스는 사용 권한 집합으로 XmlResolver를 래핑합니다. 해당 생성자는 XmlResolverEvidence, PermissionSet , String URL 개체 중 하나를 갖습니다. PermissionSetEvidence 또는 String 개체에서 계산할 수 있습니다. CreateEvidenceForUrl()  메서드를 사용하여 String 개체에서 Evidence를 계산할 수 있습니다. XmlSecureResolver는 원본으로 사용하는 XmlResolver에 대해 GetEntity 메서드를 호출하기 전에 사용 권한 집합에 대해 PermitOnly() 를 호출합니다. 이 경우 보안되지 않은 URI를 확인하려고 시도하면 보안 예외가 발생하고 실패합니다.

따라서 www.example.com의 스타일시트를 신뢰하면 XslTransform에서 다음 코드 조각으로 해당 사이트에서 가져온/포함된 스타일시트만 확인할 수 있습니다. 또한 HTTP 인터넷 리소스에 대한 액세스 권한을 제어하는 System.Net.WebPermission  클래스를 사용합니다.

// 1. 스타일시트 URL에 대한 기본 사용 권한 집합을 생성합니다.
Evidence evidence = XmlSecureResolver.CreateEvidenceForUrl(stylesheetURL);
PermissionSet myPermissions = SecurityManager.ResolvePolicy(evidence);

// 2. 신뢰할 수 있는 사이트에 대한 액세스만 허용하도록 사용 권한 집합을 수정합니다.
WebPermission myWebPermission = new WebPermission(NetworkAccess.Connect, 
"http://www.example.com");
myPermissions.SetPermission(myWebPermission);

// 3. XmlSecureResolver를 사용하여 래핑합니다.
XmlUrlResolver resolver = new XmlUrlResolver();
XmlSecureResolver sResolver = new XmlSecureResolver(resolver, 
myPermissions);

// 4. XslTransform에 스타일시트를 로드합니다.
XslTransform xslt = new XslTransform();
xslt.Load("http://www.example.com/stylesheet.xsl", sResolver);

즉, XmlSecureResolverXslTransform.Load()로 전달하면 개발자는 import/include URI를 안전하게 확인할 수 있습니다.

Document() 함수 확인

XSLT 1.0의 document() 함수를 사용하면 여러 개의 원본 문서에 대해 변환을 실행할 수 있습니다. 다음은 이 함수의 사용을 보여 주는 스타일시트 예제입니다.

스타일시트

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/root">
   <xsl:for-each select="order">
      <xsl:call-template name="processOrders" select="document(.)"/>
   </xsl:for-each>
   <xsl:for-each select="customer">
      <xsl:call-template name="processCustomers" select="document(.)"/>
   </xsl:for-each>
</xsl:template>

<xsl:template name="processOrders">
   <!-- 주문 문서 처리 -->
</xsl:template>

<xsl:template name="processCustomers">
   <!-- 고객 문서 처리 -->
</xsl:template>

</xsl:stylesheet>

XML

<root>
   <order>order1.xml</order>
   <order>order2.xml</order>
   <customer>cust1.xml</customer>
   <customer>cust2.xml</customer>
</root>

일반적인 위험과 문제점은 import/include 섹션에서 살펴본 경우와 비슷합니다. 앞에서 설명한 바와 같이 document() 함수 URI 참조는 실행 중에 확인됩니다. 확인을 위해 Transform() 메서드에 전달된 XmlResolver가 사용됩니다. 보안 교차 영역 확인을 보장하려면 XmlSecureResolver를 전달해야 합니다.

여기서 주의할 사항은 두 가지입니다.

  • 변환을 실행하는 코드에 FullTrust 사용 권한 집합이 없으면 document() 함수를 스크립트와 함께 사용할 수 없습니다.
  • 문서 URI를 확인하려는 시도가 실패하면 오류가 발생하고 변환이 종료됩니다. 대신에 document()에 대해 빈 노드 집합이 반환됩니다. 많은 사용자들이 이런 동작을 무시할 수 있는 방법에 대한 질문을 공용 뉴스 그룹에 올려놓았습니다. 변환을 종료하려는 경우 사용자 지정 확인자 를 사용하고 GetEntity()가 실패하면 예외가 발생됩니다.

스타일시트 스크립트

XSLT의 확장 기능으로 가장 많이 사용하는 것은 스크립팅일 수 있습니다. XslTransform 클래스는 C#, JScript, Visual Basic 등과 같은 스크립팅 언어를 사용할 수 있는 <msxsl:script>  확장 요소를 지원합니다. 스타일시트를 컴파일하면 스크립트 코드 블록이 System.CodeDom.Compiler  네임스페이스의 코드 생성 클래스를 사용하여 하나 이상의 메모리 내에 있는 어셈블리로 컴파일됩니다.

XSLT 개발자들이 보안에 대해 가장 염려하는 부분은 스타일시트의 스크립트입니다. 악의적인 스크립트가 컴퓨터의 보호된/시스템 리소스에 액세스할 수 있습니다. 예를 들어 하드 드라이브에서 파일을 읽거나 적절한 사용 권한 없이 권한 있는 작업을 수행하는 경우가 있습니다. 그러므로 다음과 같은 질문을 할 수도 있습니다.

  • 스타일시트 스크립트의 사용 권한을 제어할 수 있습니까?
  • 스타일시트에서 스크립트를 전혀 사용하지 못하게 할 수 있습니까?

위 두 질문에 대한 답은 예입니다.

시나리오 2: 스크립팅

브라우저에서 XSL 변환을 실행하는 웹 클라이언트 응용 프로그램을 디자인하는 시나리오를 고려하십시오. 다음은 컴퓨터의 파일을 삭제하기 위해 FileIOPermission 이 필요한 스크립트를 가진 예제 스타일시트입니다.

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:myScript="http://my.com">

<xsl:template match="/">
   <xsl:value-of select="myScript:DeleteFile()"/>
</xsl:template>

<msxsl:script language="C#" implements-prefix="myScript">
   <![CDATA[
      public void DeleteFile()
      {
         if (System.IO.File.Exists('c:\temp.txt'))
            System.IO.File.Delete('c:\temp.txt');
      }
   ]]>
</msxsl:script>
</xsl:stylesheet>

사용자는 스타일시트의 원본 위치에 따라 XSL 변환에 사용 권한을 부여하려고 합니다. 스타일시트가 신뢰할 수 있는 비즈니스 파트너의 웹 사이트에서 온 것이면 사용자는 FileIO가 포함된 사용 권한 집합을 변환에 부여하려고 합니다. 그렇지 않은 경우 기본 인터넷 영역 사용 권한으로 변환을 실행하려고 합니다.

증거 기반 스크립팅 보안

SDK 버전 1.1의 XslTransform 클래스 구현에서는 CLR Code Access Security  모델과 비슷한 스크립팅 보안을 사용합니다. Evidence  개체를 XslTransform.Load()에 전달할 수 있으며 이 증거는 스크립트 어셈블리의 사용 권한을 제어합니다.

Evidence 클래스는 실제로 코드 증거를 나타내는 개체 집합의 컨테이너입니다. 이 클래스에는 호스트와 어셈블리 증거에 해당하는 두 개의 집합이 있습니다.

  • 호스트 증거는 ControlEvidence 사용 권한이 있는 호스트에서 제공할 수 있습니다. 일반적으로 이 증거는 코드의 원본 위치에 대한 정보를 제공하며 Url , Site , Zone  개체로 구성됩니다. 빈 증거 개체를 만들고 그 개체에 Evidence.AddHost()  메서드를 사용하여 호스트 증거 개체를 추가할 수 있습니다.
  • 어셈블리 증거는 CLR 어셈블리 자체의 일부이며 어셈블리에 서명되기 이전에 생성할 때 해당 어셈블리에 추가됩니다. 개발자는 사용자 지정 증거를 어셈블리에 첨부할 수 있습니다.

자세한 내용은 Code Access Security 에서 .NET SDK 개념 설명서를 참조하십시오.

스크립트 어셈블리 컴파일을 위한 UnmanagedCode  사용 권한과 증거를 제공하려면 호출자에게 ControlEvidence  사용 권한이 있어야 합니다. 즉, 코드 실행 변환에 FullTrust 사용 권한 집합이 없으면 스크립트를 실행할 수 없다는 것입니다. 이는 매우 제한적인 방법으로 생각되지만 2차 공격을 막는 좋은 보안 방법입니다.

시나리오 2의 해결 방법

시나리오 2에서 설명한 문제로 돌아가 보겠습니다. 클라이언트 쪽 응용 프로그램에서는 스타일시트의 원본 URI를 검사할 수 있습니다.

  • URI가 신뢰할 수 있는 파트너 사이트가 아니면 다음 증거를 XslTransform.Load()로 전달합니다.
    Evidence evidence = new Evidence();
    evidence.AddHost(new Zone(SecurityZone.Internet));
    

    이렇게 하면 인터넷 영역에 대한 SecuityManager  정책에 지정된 것과 동일한 사용 권한이 스크립트 어셈블리에 주어집니다. 여기에는 기본적으로 FileIO 사용 권한이 포함되지 않습니다.

  • URI가 신뢰할 수 있는 파트너 사이트의 것이 아니면 해당 사이트에 대한 사용자 지정 사용 권한을 만들어야 합니다. 이러한 용도로 .NET Framework Configuration Tool  또는 Code Access Security Policy Tool 을 사용할 수 있습니다.

보안 스크립팅 지침

XslTransform.Load()에 정확한 증거를 전달하면 스타일시트 스크립트에 대한 XslTransform 응용 프로그램의 보안이 제어됩니다. 일반적인 지침은 다음과 같습니다.

  1. 스타일시트가 신뢰할 수 있는 응용 프로그램에서 온 것이면 스크립트에 대한 해당 어셈블리의 증거를 확인합니다. 모든 CLR Assembly 에는 해당 어셈블리에 대한 증거 개체를 제공하는 증거 속성이 있습니다.
    xslt.Load(reader, resolver, assembly.Evidence);
    
  2. 스타일시트의 원본 위치에 해당하는 URL을 신뢰할 수 있으면 URL에서 증거를 만들어 그 증거를 XslTransform.Load()에 전달합니다. Load(string)에서는 이 과정이 내부적으로 수행됩니다.
    xslt.Load(reader, resolver, 
    XmlSecureResolver.CreateEvidenceForUrl(stylesheetUrl));
    
  3. 스타일시트의 원본을 확인할 수 없을 경우에는 스타일시트 스크립트의 실행을 사용하지 않아야 합니다. 증거 개체를 가져가서 NULL을 증거로 전달하는 Load()의 오버로드를 사용합니다.
  4. Evidence 매개 변수를 갖지 않는 Load()의 오버로드는 FullTrust 사용 권한 집합으로 스크립트를 실행한다는 것을 기억하십시오. 이것은 버전 1.0과의 호환을 유지하기 위한 것입니다. XSL 변환 코드가 FullTrust 사용 권한 집합에서 실행되는 경우 프로그래머가 이 동작을 무시해야 합니다.

확장 개체

스크립트와 마찬가지로 확장 개체 는 .NET XslTransform 클래스의 XSL 변환에 프로그래밍 기능을 추가합니다. 내부적으로 XslTransform 클래스는 reflection 을 사용하여 확장 개체 메서드를 호출합니다.

스크립트와 확장 개체 중 어느 것을 사용할지는 XML 개발자가 선택합니다. 그러나 확장 개체를 사용하는 것이 더 좋습니다.

  • 확장 개체를 사용하면 캡슐화와 다시 사용 기능이 향상됩니다. 응용 프로그램에 필요한 일반 확장 기능을 식별하고 그 기능을 클래스 라이브러리에 구현하고 다시 사용할 수 있습니다. Dare Obasanjo의 EXSLT 관련 마지막 기사 에서 확장 개체를 사용합니다.
  • 스타일시트 스크립트를 사용하면 확장 개체가 길어지고 읽을 수 없으며(스크립트를 문서화하지 않은 경우) 유지 관리하기 어려워집니다.
  • 스타일시트 스크립트에서는 .NET SDK 네임스페이스의 하위 집합 만 지원합니다. 이러한 네임스페이스 밖에서 클래스를 사용하려면 클래스 이름이 정규화된 이름이어야 합니다.

여기서 발생할 수 있는 보안상 허점은 무엇입니까? XSL 변환을 실행하는 반 정도 신뢰할 수 있는 코드에서 완전 신뢰할 수 있는 어셈블리의 확장 개체를 추가하면 원본 응용 프로그램에 대한 사용 권한 향상이 이루어집니다. 그러므로 확장 개체는 코드가 FullTrust 사용 권한 집합으로 실행될 경우에만 사용할 수 있습니다. 호출자에게 FullTrust 사용 권한 집합이 없으면 XsltArgumentList에 대한 AddExtensionObject()  메서드가 보안 예외를 발생시킵니다. 이렇게 하면 확장 코드가 실행될 때 사용 권한이 향상되지 않습니다.

결론

이 기사에서는 XSLT 1.0 변환 언어와 Microsoft 특정 확장의 일부 기능에 관련된 보안 위험을 검토해 보았습니다. 또한 XslTransform 클래스로 보안 코드를 작성하는 동안 수행할 수 있는 최상의 방법도 알아보았습니다. 일반적으로 XSLT 응용 프로그램이 완전히 신뢰할 수 있는 환경에서 실행될 때 보안 위협에 대해 신중하게 검사해야 합니다. 완전히 신뢰할 수 없는 환경인 경우 XslTransform이 스크립트, 확장 개체, document() 함수를 사용할 수 없도록 지정하여 보안 침해를 막습니다.

감사의 말

이 기사를 검토할 때 귀중한 조언을 제공하고 지원해 주신 Dare Obasanjo와 Microsoft WebData XML 팀 구성원들에게 감사 드립니다.


Prajakta Joshi는 Microsoft의 WebData XML 팀 구성원이며 .NET Framework의 System.Xml 네임스페이스의 XPath/XSLT 구성 요소와 관련된 작업을 하고 있습니다.

이 기사에 대한 질문이나 설명은 언제든지 GotDotNet의 Extreme XML Message Board 에 게시해 주십시오.




최종 수정일: 2003년 10월 20일
Top of Page Top of Page


Microsoft