보안 공부/소스코드 보안약점 진단

소스코드 보안약점 진단 - XPath 삽입

H.J.World 2021. 12. 16. 10:10
728x90
반응형

소스코드 보안약점 진단 // 소프트웨어 보안약점 진단 // SW 보안약점 진단과 같이 다양한 이름으로 불리는 진단 과업 중 하나이다.

SW개발보안은 해킹 등 사이버공격의 원인인 보안약점을 SW개발단계에서 사전에 제거하고 SW 개발 생명주기의 각 단계별로 수행하는 일련의 보안활동을 통하여 안전한 SW를 개발·운영하기 위한 목적으로 적용하는 개발체계이다.

해당 내용은 KISA에서 발간하는 취약점 진단 가이드 항목을 기준으로 작성한다.

 

8. XPath 삽입

가. 개요

외부입력값을 적절한 검사과정 없이 XPath 쿼리문 생성을 위한 문자열로 사용하면, 공격자는 프로 그래머가 의도하지 않았던 문자열을 전달하여 쿼리문의 의미를 왜곡시키거나 그 구조를 변경하고 임의의 쿼리를 실행하여 인가되지 않은 데이터를 열람할 수 있다.

나. 보안대책

XPath 쿼리에 사용되는 외부 입력데이터에 대하여 특수문자(“, [, ], /, =, @ 등) 및 쿼리 예약어 필터 링을 수행하고 파라미터화된 쿼리문을 지원하는 XQuery를 사용한다.

다. 코드예제

아래 예제에서는 nm과 pw에 대한 입력값 검증을 수행하지 않으므로 nm의 값으로 “tester”, pw의 값으로 “x’ or ‘x’=‘x”을 전달하면 아래와 같은 질의문이 생성되어 인증과정을 거치지 않고 로그인할 수 있다.

“//users/user[login/text()=‘tester’ and password/text()=‘x’ or //‘x’=‘x’]/home_dir/text()”

- 안전하지 않은 코드의 예 JAVA -

// 프로퍼티로부터 외부 입력값 name과 password를 읽어와 각각 nm, pw변수에 저장
1: String nm = props.getProperty("name");
2: String pw = props.getProperty("password");
3: ......
4: XPathFactory factory = XPathFactory.newInstance();
5: XPath xpath = factory.newXPath();
6: ......
// 검증되지 않은 입력값 외부 입력값 nm, pw 를 사용하여 안전하지 않은 질의문이 작성되어 expr 
변수에 저장된다.
7: XPathExpression expr = xpath.compile("//users/user[login/text()='"+nm+"' and 
password/text()='"+pw+"']/home_dir/text()");
// 안전하지 않은 질의문이 담긴 expr을 평가하여 결과를 result에 저장한다.
8: Object result = expr.evaluate(doc, XPathConstants.NODESET);
// result의 결과를 NodeList 타입으로 변환하여 nodes 저장한다.
9: NodeList nodes = (NodeList) result;
10: for (int i=0; i<nodes.getLength(); i++) {
11: String value = nodes.item(i).getNodeValue();
12: if (value.indexOf(">") < 0) {
// 공격자가 이름과 패스워드를 확인할 수 있다.
13: System.out.println(value);
14: }20: 
15:}

 

- 안전한 코드의 예 JAVA -

다음의 예제는 XQuery를 사용하여 미리 쿼리 골격을 생성함으로써 외부입력으로 인해 쿼리 구조가 바뀌는 것을 막을 수 있다.

[ login.xq 파일 ]
declare variable $loginID as xs:string external;
declare variable $password as xs:string external;
//users/user[@loginID=$loginID and @password=$password]
// XQuery를 이용한 XPath Injection 방지
1: String nm = props.getProperty("name");
2: String pw = props.getProperty("password");
3: Document doc = new Builder().build("users.xml");
//파라미터화된 쿼리가 담겨있는 login.xq를 읽어와서 파라미터화된 쿼리를 생성한다.
4: XQuery xquery = new XQueryFactory().createXQuery(new File("login.xq"));
5: Map vars = new HashMap();
// 검증되지 않은 외부값인 nm, pw를 파라미터화된 쿼리의 파라미터로 설정한다.
6: vars.put("loginID", nm);
7: vars.put("password", pw);
// 파라미터화된 쿼리를 실행하므로 외부값을 검증없이 사용하여도 안전하다.
8: Nodes results = xquery.execute(doc, null, vars).toNodes();
9: for (int i=0; i<results.size(); i++) {
10: System.out.println(results.get(i).toXML());21:
11:}

 

- 안전한 코드의 예 JAVA -

파라미터화된 쿼리를 지원하는 XQuery 구문으로 대체할 수 없는 경우에는 XPath 삽입을 유발할 수 있는 문자들을 입력값에서 제거하고 XPath 구문을 생성, 실행하도록 한다.

// XPath 삽입을 유발할 수 있는 문자들을 입력값에서 제거
1: public String XPathFilter(String input) {
2: if (input != null) return input.replaceAll("[',\\[]", "");
3: else return "";
4: }
5: ......
// 외부 입력값에 사용
6: String nm = XPathFilter(props.getProperty("name"));
7: String pw = XPathFilter(props.getProperty("password"));
8: ......
9: XPathFactory factory = XPathFactory.newInstance();
10: XPath xpath = factory.newXPath();
11: ......
//외부 입력값인 nm, pw를 검증하여 쿼리문을 생성하므로 안전하다.
12: XPathExpression expr = xpath.compile("//users/user[login/text()='"+nm+"' and 
password/text()='"+pw+"']/home_dir/text()");
13: Object result = expr.evaluate(doc, XPathConstants.NODESET);
14: NodeList nodes = (NodeList) result;
15: for (int i=0; i<nodes.getLength(); i++) {
16: String value = nodes.item(i).getNodeValue();
17: if (value.indexOf(">") < 0) {
18: System.out.println(value);
19: }
20:}
21: .....

 

라. 진단방법

XPath 객체를 통해 쿼리 스트링이 컴파일 되는 부분을 확인하고(①), XPath 쿼리스트링에 사용되는 변수가 외부 입력값 인지 확인한 후(②) 변수에 대한 필터링 모듈이 존재하는지 확인한다. 필터링 모듈이 존재하거나 관련 프레임워크에서 적절하게 조치된 경우엔 안전하다고 판정한다.

1: …
2: String acctID = request.getParameter(“acctID”);---------------②
3: String query = null;
4: if(acctID != null) {
5: StringBuffer sb = new StringBuffer(“/accounts/account[acctID=’”);
6: sb.append(acctID);------------------------------②
7: sb.append(“’]/email/text()”);
8: query = sb.toString();
9: }
10: DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
11: domFactory.setNamespaceAware(true);
12: DocumentBuilder builder = domFactory.newDocumentBuilder();
13: Document doc = builder.parse(“accounts.xml”);
14: XPathFactory factory = XPathFactory.newInstance();
15: XPath xpath = factory.newXPath();
16: XPathExpression expr = xpath.compile(query);-----------------①
17: Object result = expr.evaluate(doc, XPathConstants.NODESET);
18:

 

- 정탐코드의 예 -

다음의 예제에서는 name의 값으로 “”user1””, passwd의 값으로 “”’ or “=’””을 전달하면 다음과 같은 쿼리문이 생성되어 인증과정을 거치지 않고 로그인할 수 있어 취약하다고 판정한다.

(//users/user[login/text()=’user1’ or ‘’=’’ and password/text() = “” or “”=””]/home_dir/text())

1: …
2: // 외부로부터 입력을 받음
3: String name = props.getProperty(“name”);
4: String passwd = props.getProperty(“password”);
5: …
6: XPathFactory factory = XPathFactory.newInstance();
7: XPath xpath = factory.newXPath();
8: …
9: // 외부 입력이 xpath의 인자로 사용
10: XPathExpression expr = xpath.compile(“//users/user[login/text()=’” + name + “’ and
password/text() = ‘” + passwd + “’]/home_dir/text()”);
11: Object result = expr.evaluate(doc, XPathConstants.NODESET);
12: NodeList nodes = (NodeList) result;
13: for (int i = 0; i < nodes.getLength(); i++) {
14: String value = nodes.item(i).getNodeValue();
15: if (value.indexOf(“>”) < 0) {
16: System.out.println(value);
17: }
18: …
728x90
반응형