본문 바로가기

Web Security/Secure Coding

시큐어 코딩 (XQuery Injection)

XQuery Injection 공격이란? 

 XQuery를 사용하여 XML 데이터에 대한 동적 쿼리문을 생성할 때 사용하는 외부 입력 값에 대해 적절한 검증 절차가 존재하지 않을 경우, 공격자가 쿼리문의 구조를 임의로 변경하여 허가되지 않은 데이터를 조회하거나 인증 절차를 우회할 수 있게 되는 공격.

 

XQuery Injection 공격 원리 

 1. 공격자가 XQuery Injection을 시도

 2. XML 데이터에 대한 조작된 동적 쿼리문 생성

 3. 조작된 XQuery 문 실행 

 4. 서버는 실행된 결과(공격 결과)를 공격자에게 전달 

 

예제 코드를 보며 XQuery Injection 이 일어나는 이유를 살펴보자. 

 

[안전하지 않은 코드]

```
    String name = props.getProperty("name"); 
    
    // Connection 
    Hashtable env = new Hashtable(); 
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LadpCtxFactory"); 
    env.put(Context.PROVIDER_URL, "ladp://localhost:389/o=rootDir"); 
    javax.naming.directory.DirContext ctx = new InitialDirContext(env); 
    java.xml.xquery.XQDataSource xqds = (javax.xml.xquery.XQDataSource) ctx.look-up("xqj/personnel"); 
    javax.xml.xquery.XQConnection conn = xqds.getConnection(); 
    
    // 취약한 코드 
    String es = "doc('user.xml')/userlist/user[uname='" + name + "']"; 
    // 입력 값이 XQuery의 인자로 사용 
    XQPreparedExpression expr = conn.prepareExpression(es); 
    XQResultSequence result = expr.executeQuery(); 
    while(result.next()) { 
         ...
    }
 ```

위 코드를 살펴 보면, 외부 입력 값을 받은 것을 XQuery 문에 바로 포함시켜 실행하는 것을 알 수 있다. 이러한 경우, XQuery상의 쿼리 구조 변경시키는 입력 값이 들어오게 되면 XQuery Injection 이 실행될 것이다. 

 

이를 막기 위해선, 아래와 같이 preparedExpression 을 사용하여 bindString, bindInt 등으로 인자 형식으로 전달해줍니다. 이와 같이 인자 전달을 하게 되면, 외부에서 입력된 값은 단순히 문자열로 취급되어 XQuery 상의 쿼리 문법으로 인식되지 않아 쿼리 구조를 변경시킬 수 없게 됩니다. 

 

[안전한 코드] 

```
    String name = props.getProperty("name"); 
    
    // Connection 
    Hashtable env = new Hashtable(); 
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LadpCtxFactory"); 
    env.put(Context.PROVIDER_URL, "ladp://localhost:389/o=rootDir"); 
    javax.naming.directory.DirContext ctx = new InitialDirContext(env); 
    java.xml.xquery.XQDataSource xqds = (javax.xml.xquery.XQDataSource) ctx.look-up("xqj/personnel"); 
    javax.xml.xquery.XQConnection conn = xqds.getConnection(); 
    
    // Secure Coding 
    String es = "doc('user.xml')/userlist/user[uname='$xpathname']"; 
    // 입력 값이 XQuery의 인자로 사용 
    XQPreparedExpression expr = conn.prepareExpression(es); 
    // Secure Coding 
    expr.bindString(new QName("xpathname"), name, null); 
    XQResultSequence result = expr.executeQuery(); 
    while(result.next()) { 
         ...
    }
 ```

쿼리 구조를 변경 시킬 수 없는 이유를 이해하기 위해서는 Expression 과 preparedExpression의 동작 원리를 이해하고 있으면 어떤 방식으로 인해 보안이 이루어지는지 알 수 있으며, bind[타입] 메소드를 사용하느냐 안하느냐에 따라 XQuery Injection 공격을 막느냐 못막느냐가 결정되기 때문에 이러한 부분을 이해하는 것이 중요한 것 같다. 

 

Expression과 preparedExpression 방식 차이점에 대해 더 알아보고 싶다면, 아래 링크를 참고하시면 됩니다 :)

XQuery Java API : http://www09.sigmod.org/sigmod/record/issues/0912/p07.article.cappellen.pdf

 

 

참고 문헌

[1] 시큐어 코딩 보안 가이드 https://www.kisa.or.kr/public/laws/laws3_View.jsp?mode=view