메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

XML의 실시간 암호화를 위한 XSLT 확장

한빛미디어

|

2002-04-17

|

by HANBIT

12,147

저자: 더그 티드웰, 역 『소스 코드로 배우는 XSLT』 역자 장은영

XSLT는 XML 문서를 변환해주는 유연하면서도 강력한 언어이다. 그러나 그 능력이 아무리 막강하다 하더라도, XSLT가 모든 것을 지원하는 것은 아니다. 따라서 XSLT에서 지원하지 않는 것들을 실행할 경우 확장 요소(extension elements)와 확장 함수(extension functions)를 작성해 주어야 할 필요가 있다. 이 기사에서는 XML 문서의 일부를 암호화하는 확장 함수를 작성해 봄으로써 XSLT의 확장 기법에 대하여 알아 본다.

XSLT 1.0 규약에 확장 기법이 정의되어 있다는 것은 우리에게 반가운 소식이다. 그렇지만 안타깝게도 확장된 부분이 어떻게 동작해야 하는가에 대한 세부적인 내용은 규약에 정의되어 있지 않아, 프로세서마다 조금씩 차이가 있다. 평소에 즐겨 사용하는 XSLT 프로세서에서 동작하는 확장 함수나 확장 요소를 작성하면, 이 함수와 요소가 작동하는 것을 아무도 방해할 수 없다. 반면 사용하는 XSLT 프로세서를 바꾸려면, 관련된 코드를 수정해야 하는 단점이 있다.

여기에서 사용할 예제는 Xalan XSLT 프로세서에 정의된 인터페이스를 사용하여 자바로 작성되었다. 확장 함수를 작성할 때 우리는 XSLT 프로세서에서 코드로 어떻게 데이터를 옮겨 오고, 되돌려 놓는 법을 알아 내어야 할 것이다. (만약 자바를 잘 모른다면 다른 언어를 사용할 수도 있다. 자바 버전의 Xalan은 IBM의 Bean Scripting Framework도 지원한다. 이것은 JPython[Jython], JavaScript, Perl Script, Jacl 등의 스크립트 언어로 XSLT를 확장할 수 있게 해준다.)

암호화가 필요한 문서

시작에 앞서 예제 문서를 한번 보자. 다음은 고객의 주문서를 나타내는 XML 문서이다.


  
    
      Turnip Twaddler
      3
      9.95
    
    
      Snipe Curdler
      1
      19.95
    
  
  
    Doug Tidwell
    1234 Main Street
    Raleigh
    11111
  
  
    American Express
    1234 567890 12345
    
  

이 문서에서 보듯이 보안상 숨겨야 할 정보를 담고 있는 요소는 라는 것을 한 눈에 알 수 있다. 우리는 IBM의 alphaWorks 웹 사이트에서 얻을 수 있는 XML 보안 유틸리티 패키지인 XSS4J(XML Security Suite)의 요소 단위 암호화(element-wise encryption) 함수를 사용할 것이다. 이 기술은 JCE(Java Cryptography Extension) 및 W3C와 IETF가 공동 작업중인 XML 디지털서명(XML Digital Signatures)을 기반으로 만들어 졌다. 요소 단위의 암호화를 사용하여 예제로 보았던 문서를 다음과 같은 형태의 코드로 변환할 수 있다.

소스 코드로 배우는 XSLT
예제의 코드에서 알 수 있듯이 요소는 요소로 대체되었다. 본래의 문서 형식을 모르는 사람에게는 암호화된 요소의 원래 내용이 무엇이었는지 알아낼 수 있는 단서조차 제공되지 않는다. 는 두 개의 속성을 가진 하나의 비어있는 요소일 수도 있고, 많은 텍스트를 포함하고 있는 요소일 수도 있다. 또는 그 아래에 여러 단계의 자손을 가진 요소일 수도 있다. 데이터를 해석할 수 있는 적합한 키가 없다면 이 데이터는 단지 쓰레기에 불과한 것이다.

확장 함수의 설계

다양한 요소를 암호화하는 데에 XSLT 스타일시트를 사용할 수 있도록 하기 위해 필요한 것은 확장 함수를 작성하는 일이다. 여기에는 여러 가지 장점이 있다.
  • 만약 문서의 다른 부분을 암호화하고 싶다면, 스타일시트를 약간 수정하는 것으로 일을 끝낼 수 있다.


  • 논리적인 판단을 통해 사용자에 따라 서로 다른 부분이 암호화되도록 할 수 있다. 예를 들어 의료 관련 부서에 근무하는 사람이 아니라면 병원 기록을 볼 수 없도록 하고, 인사팀에 근무하는 사람이 아니라면 연봉에 대한 기록을 볼 수 없게 할 수 있다.


  • 암호화 기술에 대한 구체적인 내용은 모두 서버에 보관할 수 있다. 내용의 일부가 암호화된 문서를 받는 사용자는 이 문서가 자신이 문서를 요청한 후에 암호화되었는지, 다른 사용자들도 똑같이 암호화된 문서를 보게 될지, 또는 본래의 문서가 어떤 모습인지 알 수가 없다.
지금부터 만들게 될 확장 함수는 XML 문서의 암호화하려는 노드와 암호화 과정에 넘겨 주어야 하는 매개변수들을 인자로 갖는다. 이 확장 함수를 호출하는 방법은 다음과 같은 형태가 될 것이다.
  
    
  
함수에 인자로 여러 가지를 전달했다. 첫번째로 (축약된 XPath 표현식 "."으로 나타낸) 현재 노드가 전달되고, 그 다음으로 JCE 키스토어(keystore, 암호화 키에 대한 정보를 저장하는 곳)에 대한 비밀번호와 키스토어 파일의 이름(여기에서는 알아 보기 쉽게 이름을 "keystore"라 붙였음)이 전달된다. 그 다음에 따라오는 것이 키의 별명(alias)이다(앞에서와 같은 이유로 이름을 "key"라 붙였다). 함수에 마지막으로 넘겨 주는 항목은 XSS4J가 사용하는 구성 파일(configuration file)의 이름이다. 이 파일의 내용은 다음과 같다.


  
    
    
      key
    
  
  

이 파일은 데이터 암호화에 사용되는 암호 알고리즘과 관련된 여러 가지 세부사항을 정의한다. 여기에서는 무작위로 생성된 TripleDES 키를 사용할 것이며, 이 키는 RSA 키로 암호화될 것이다(이러한 기법은 키 트랜스포트(key transport)라 부르기도 함). 구성 파일은 우리가 사용하는 XSS4J 클래스의 필수 사항 중 하나이다. 세부 사항을 별도의 파일에 명시할 경우, 만약 사용하는 알고리즘을 바꾸고 싶다면 구성 파일만 수정하면 되므로 유연성을 더 높여준다.

지금까지 우리는 확장 함수 인자를 정의했다. 이 인자들은 데이터 암호화에 사용되는 XSS4J 클래스의 요구사항과 암호화할 문서의 구조에 따라 선택되었다. 이제 남은 것은 실제 코드를 작성하는 방법을 자세히 알아 보는 것이다.

확장 함수의 작성

마지막 단계는 실제로 문서에서 암호화가 필요한 부분을 변환하는 코드를 작성하는 것이다. 우리는 이미 스타일시트에서 메소드의 서명을 보았다. 아래 표는 인자, 스타일시트에서 인자의 데이터형, 확장 함수에서 인자의 데이터형을 보여 준다.
확장 함수 매개변수
XSLT 데이터형
자바 데이터형
. [The current node] An XPath node-set org.w3c.dom.NodeList
"storepass" A string A string
"keystore" A string A string
"key" A string A string
"crypto-details.xml" A string A string

서로 전달되는 데이터 형은 대부분 문자열 형태이기 때문에 변환 과정의 대부분은 단순하고 명확하다. 복잡한 부분은 NodeList 객체이다. NodeList는 문서 객체 모델(DOM, Document Object Model)에 정의되어 있으며, 문서에서 순서가 정해진 노드들의 집합을 나타낸다. 우리는 이 노드들 중 하나(여기에서는 단 하나만을 사용했지만, 다른 XML 문서에서는 여러 개를 사용할 수도 있다)를 XEncryption.encrypt() 함수의 입력으로 받아 들일 것이다.

따라서 확장 함수가 실제로 갖게 되는 시그너처는 다음과 같다.
  public static XNodeSet encryptNode(NodeList nl, String passPhrase,
                                     String keyStore, String keyName,
                                     String encryptionTemplate)
여기에서 함수에 사용된 인자와 위에서 보았던 표의 내용이 어떻게 일치하는가를 볼 수 있다. 이제 확장함수가 XSLT 프로세서로부터 필요한 데이터를 받았으므로, 실제로 데이터를 암호화 하는 작업을 수행하는 XEncryption.encrypt() 함수를 호출할 차례이다. 우리가 사용할 함수는 다섯 개의 매개변수를 사용할 것이다.
XEncryption.encrypt() 매개변수
매개변수를 얻는 곳
암호화할 데이터 XSLT 프로세서 우리는 NodeList를 받을 것이며, NodeList의 첫 번째 노드(이 예에서는 유일한 노드이기도 하다)가 암호화 해야 하는 대상이다
요소의 내용을 암호화할 것인가를 나타내는 플래그 항상 false이다
구성 파일의 를 나타내는 DOM 요소 XML 구성 파일의 파싱 파일의 이름은 XSLT 프로세서로부터 전달된다
자바 키 객체 (java.security.Key) 자바 키스토어 키스토어의 비밀번호, 키스토어의 이름, 키의 별명은 XSLT 프로세서로부터 전달된다
구성 파일의 를 나타내는 DOM 요소 XML 구성 파일의 파싱. 여기에서도 파일의 이름은XSLT 프로세서로부터 전달된다

이제 encrypt()를 호출하는 데에 필요한 다섯 개의 매개변수를 얻는 일만 남았다. 앞의 표에서 처음 두 개의 매개변수에 사용할 값은 이미 알고 있으므로, 세 번째 항목으로 넘어가자. 먼저 XML 구성 파일을 파싱하기 위하여 DOMParser 객체를 생성한다. 구성 파일의 루트 요소는 요소이므로, DOM 트리의 루트 요소가 필요한 세 번째 매개변수가 된다. 이것을 코드로 나타내면 다음과 같다.
   DOMParser parser = new DOMParser();
   parser.setIncludeIgnorableWhitespace(false);
   parser.parse(encryptionTemplate);
   doc = parser.getDocument();
   ee = doc.getDocumentElement();
   Element ek = 
     (Element)(ee.getElementsByTagName("EncryptedKey").item(0));
이 코드에서 DOM 트리의 문서 요소(document element)는 요소를 나타낸다. 또한 이 요소의 첫 번째 요소를 얻어, XEncryption.encrypt()의 다섯 번째 매개변수로 사용한다. (DOM의 getElementsByTagName 메소드는 그 이름을 갖는 모든 자식 요소들로 구성된 NodeList를 리턴한다. 이 NodeList의 첫번째 항목을 저장해 두었다가 나중에 사용할 것이다.)

마지막으로 자바 키스토어로부터 얻는 키가 남아 있다. 이를 위해 XSLT 프로세서로부터 얻은 비밀번호를 사용하여 키스토어를 열어야 할 필요가 있다. 일단 명시된 파일을 열면, 우리가 알고 있는 별명에 해당하는 키를 얻어야 한다. 만약 이 단계 중 어느 하나라도 실패한다면 코드는 예외를 전달하고 중단될 것이다. 실제 코드는 다음과 같다.
   KeyStore ks = KeyStore.getInstance("JKS");
   ks.load(new FileInputStream(keyStore), passPhrase.toCharArray());
   Key k = null;
   if (ks.isKeyEntry(keyName)) 
     k = (ks.getCertificate(keyName)).getPublicKey();
이 예에서 자바 키스토어(JKS는 Java keystore를 의미)를 생성하고 XSLT 프로세서로부터 얻은 파일 이름과 비밀번호를 사용하여 키스토어를 로딩 하려는 시도를 한다. 일단 키스토어가 로딩 되면 프로세서로부터 얻은 키 이름으로부터 공개 키(public key)를 얻는다.

이제는 XEncryption.encrypt()를 실행하는 데에 필요한 모든 데이터를 얻었다. 이 함수를 실행하는 코드는 다음과 같다.
   encrypted = xenc.encrypt((Element)nl.item(0), false, ee, k, ek);
   encryptedResult = new XNodeSet(encrypted);
이 코드에서 encrypted는 DOM 요소이다. 우리는 이것을 사용하여 XNodeSet을 생성한다. XNodeSet은 XPath의 노드 집합(node-set)을 나타내는 Xalan 고유의 클래스이다. 그리고 나서 생성된 XNodeSet을 리턴하면 모든 과정이 끝난다.
   return encryptedResult;
이렇게 변환한 결과는 앞에서 보았던 암호화된 문서가 된다. 요소가 암호화된 것이다. 이 기술은 우리에게 흥미로운 시나리오를 던져준다. 요즈음 우리가 웹 사이트에서 주문을 하고 시큐어 소켓(secure socket)을 통하여 신용카드 번호를 전송해도 별로 부담감을 갖지 않는다. 여기에는 물론 온라인 상점의 직원이 나의 신용카드 번호를 부당하게 사용하지 않는다는 믿음이 전제가 된다. 그런데 만약 나의 개인 키(private key)와 신용카드사의 공개 키를 사용하여 신용카드 정보를 암호화한다면 어떻게 될까? 그 상점은 어떤 데이터도 볼 수 없게 되고, 단지 신용카드사에 이를 전달하여 정보 조회를 하게 될 것이다. 신용카드사는 그의 개인키와 함께 나의 공개키를 사용하여 데이터를 해석할 수 있고, 이 데이터가 정말로 다른 사람이 아닌 내가 보낸 것인지 확인할 수 있다. 그리고는 상점에 인증 코드를 보내 줄 수 있다.

요약

이렇게 코딩이 끝나면 XSLT 스타일시트에서 호출할 수 있는 강력한 확장 함수를 갖게 된다. 앞에서 언급한 바와 같이 스타일시트에 논리적인 판단을 내리는 코드를 사용하여 문서의 일부분이 특정 사용자에게만 암호화되거나, 특별한 경우에만 암호화되도록 만들 수 있다. 대부분의 확장 함수는 비슷한 방법으로 작성된다. 즉, 별도의 외부 패키지에서 제공하는 기능을 사용하고 싶다면 확장 함수를 작성하는 데에는 XSLT 환경으로부터 필요한 데이터를 얻고, 이를 확장 함수에 전달하여 적절한 결과를 생성하고, 이 결과를 다시 XSLT 환경으로 전달해 주는 과정이 필요하다. XSLT 프로세서와 다른 코드를 결합하기 위해 확장 함수를 만드는 것에 익숙해 지고 나면, 스타일시트가 어떤 일을 할 수 있는가에 대하여 감탄을 금치 못할 것이다.

참고 자료

도움이 될만한 다양한 자료를 다음과 같이 소개한다.
  • 『소스 코드로 배우는 XSLT』는 확장 함수와 확장 요소에 대한 예제를 통하여 XSLT 확장 기법을 심도있게 다룬다. 자세한 정보는 『소스 코드로 배우는 XSLT』를 참고해보자.


  • XSS4J(XML Security Suite)는 IBM의 alphaWorks 사이트에서 얻을 수 있다. 이 패키지는 다양한 샘플 애플리케이션, DOMHASH 알고리즘, 그리고 XML과 ASN.1을 서로 변환할 수 있는 코드를 포함하고 있다. XSS4J는 IBM의 도쿄 연구소에서 Xerces 파서의 모태를 개발한 팀에 의하여 탄생되었다.


  • Xalan 스타일시트 엔진은 아파치 XML 프로젝트에서 얻을 수 있다. 이 글에서 사용한 Xerces 파서는 Xalan이 포함된 xerces.jar이다.


  • JCE(Java Cryptography Extension)에 대한 더욱 자세한 내용은 java.sun.com/products/jce에서 찾을 수 있다. 이 사이트에서는 암호화 서비스를 제공하는 회사 및 단체들의 목록도 찾을 수 있다.


  • IETFW3C에서도 디지털서명에 대한 자료를 얻을 수 있다.
이 글의 예제로 사용된 코드는 모두 코드 목록에서 볼 수 있다.

더그 티드웰(Doug Tidwell)은 IBM의 수석 프로그래머로 십 년 이상을 마크업 언어와 함께 했다. 1997년 처음 열린 XML 컨퍼런스에서 연설을 했고 전 세계를 돌아다니며 XML을 가르쳐왔다. IBM의 개발자를 위한 사이트(developerWorks)에 XML과 웹 서비스와 관련된 기사를 쓰기도 했다.
TAG :
댓글 입력
자료실

최근 본 상품0