자바

JAVA 보안 개발 가이드

1절. 입력 데이터 검증 및 표현

1. 크로스 사이트 스크립트 공격 취약점(XSS)

가. 정의

외부에서 입력되는 검증되지 않은 입력이 동적 웹페이지의 생성에 사용될 경우, 전송된 동적 웹페이지를 열람하는 접속자의 권한으로 부적절한 스크립트가 수행되어 정보 유출 등의 피해를 입힐 수 있다.

나. 안전한 코딩기법

외부에서 입력한 문자열을 사용하여 결과 페이지를 생성할 경우, replaceAll() 등과 같은 메소드를 사용하여 위험한 문자열을 제거하여야 한다.

다. 예제

안전하지 않은 코드 예제-HTML


1: <%@page contentType="text/html" pageEncoding="UTF-8"%>
2: <html>
3: <head>
4: <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5: </head>
6: <body>
7: <h1>XSS Sample</h1>
8: <%
9: <!- 외부로 부터 이름을 받음 -->
10: String name = request.getParameter("name");
11: %>
12: <!-- 외부로 부터 받은 name이 그대로 출력 -->
13: <p>NAME:<%=name%></p>
14: </body>
15: </html>

위 예제는 외부 입력을 name 값으로, 특별한 처리과정 없이 결과 페이지 생성에 사용하고있다. 만약 악의적인 공격자가 name 값에 다음 아래의 스크립트를 넣으면, 희생자의 권한으로 attack.jsp 코드가 수행되게 되며, 수행하게 되면 희생자의 쿠키정보 유출 등의 피해를 주게 된다. 


(예 : <script>url = "http://devil.com/attack.jsp;</script>)

안전한 코드 예제


1: <%@page contentType="text/html" pageEncoding="UTF-8"%>
2: <html>
3: <head>
4: <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5: </head>
6: <body>
7: <h1>XSS Sample</h1>
8: <%
9: <!-- 외부로 부터 이름을 받음 -->
10: String name = request.getParameter("name");
11:
12: <!-- 외부의 입력값에 대한 검증을 한다. -->
13: if ( name != null ) {
14: name = name.replaceAll("<","&lt;");
15: name = name.replaceAll(">","&gt;");
16: } else {
17: return;
18: }
19: %>
20: <!-- 외부로 부터 받은 name에서 ‘위험 문자’를 제거한 후 출력 -->
21: <p>NAME:<%=name%></p>
22: </body>
23: </html>

위의 예제와 같이 외부 입력 문자열에서 replaceAll() 메소드를 사용하여 “<”와 “>“같이 HTML에서 스크립트 생성에 사용되는 모든 문자열을 ”&lt;”와“&gt;“로 변경함으로써 악의적인 스크립트 수행의 위험성을 줄일 수 있다. 그러나 이러한 방법이 위험성을 완전히 제거했음을 의미하지는 않는다.

라. 참고문헌

[1] CWE-80 크로스 사이트 스크립트 공격 취약점(XSS) - http://cwe.mitre.org/data/definitions/80.html 
[2] OWASP Top 10 2010 - (OWASP 2010) A2 Cross-Site Scripting(XSS) 
[3] SANS Top 25 2010 - Insecure Interaction Between Components, RANK 1 CWE-79 ImproperNeutralization of Input During Web Page Generation ('Cross-site Scripting')

2. SQL 삽입(SQL Injection)

가. 정의

공격자가 외부 입력을 통해서 SQL 명령어를 수행할 수 있다. 즉 외부 입력한 데이터에 대한 유효성을 점검하지 않아 쿼리 로직이 변경 되어 공격자의 의도대로 타인의 정보 유출 또는 DB의 변경이 발생할 수 있다.

나. 안전한 코딩기법

preparedStatement 클래스와 하위 메소드 executeQuery(), execute(), executeUpdate()를 사용하는 것이 바람직하다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: PreparedStatement stmt = null;
3:
4: try {
5: ……
6: // 외부 환경에서 테이블명(tablename)과 사용자명(name)을 입력받는다.
7: String tableName = props.getProperty("jdbc.tableName");
8: String name = props.getProperty(" jdbc.name" );
9: String query = "SELECT * FROM " + tableName + " WHERE Name =" + name;
10:
11: // 사용자가 입력한 데이터가 SQL문에 그대로 반영된다.
12: // 사용자가 타인의 정보를 보기 위한 SQL을 사용자명(name)에 입력할 수 있다.
13: stmt = con.prepareStatement(query);
14: rs = stmt.executeQuery();
15: ResultSetMetaData rsmd = rs.getMetaData();
16: ……
17: while (rs.next()) { …… }
18: dos.writeBytes(printStr);
19: } catch (SQLException sqle) { …… }
20: finally { …… }
21: ……

위 예제는 외부 입력으로부터 tableName과 name을 받아서 SQL 질의문을 생성하고 있다. 
만약 name의 값으로 “name' OR 'a'='a”과 같은 문자열이 전달되면, 다음과 같은 쿼리가생성되어 테이블 내의 모든 사용자 정보를 얻을 수 있다. 


(SELECT * FROM userTable WHERE Name ='name' OR 'a'='a')


또한 name 값으로 [“name'; DELETE FROM userTable; –”]를 주게 되면 다음과 같은 쿼리가 생성되어 테이블을 모두 삭제할 수 있다. 


(SELECT * FROM userTable WHERE Name ='name'; DELETE FROM userTable; --')

안전한 코드 예제


1: ……
2: PreparedStatement stmt = null;
3:
4: try {
5: ……
6: String tableName = props.getProperty("jdbc.tableName");
7: String name = props.getProperty("jdbc.name");
8:
9: // 동적 질의문으로 생성되지 않도록 PreparedStatement를 사용한다.
10: String query = "SELECT * FROM ? WHERE Name = ? " ;
11: stmt = con.prepareStatement(query);
12: // 사용자가 입력한 데이터를 setXXX()함수로 셋팅한다.
13: stmt.setString(1, tableName);
14: stmt.setString(2, name);
15:
16: rs = stmt.executeQuery();
17: ResultSetMetaData rsmd = rs.getMetaData();
18: int columnCount = rsmd.getColumnCount();
19: String printStr = "";
20: while (rs.next()) { …… }
21: dos.writeBytes(printStr);
22: } catch (SQLException sqle) { …… }
23: finally { …… }
24: ……

위의 예제와 같이 인자를 받는 PreparedStatement 객체를 상수 스트링으로 생성하고, 인자 부분을 setXXX() 메소드로 설정하여, 외부의 입력이 질의문의 구조를 바꾸는 것을 방지할 수 있다

라. 참고문헌

[1] CWE-89 SQL 삽입 - http://cwe.mitre.org/data/definitions/89.html 
[2] OWASP Top 10 2010 - (OWASP 2010) A1 - Injection 
[3] SANS Top 25 2010 - Insecure Interaction Between Components, RANK 2 CWE-89 ImproperNeutralization of Special Elements used in an SQL Command ('SQL Injection')

3. SQL 삽입공격: JDO(SQL Injection: JDO)

가. 정의

외부의 신뢰할 수 없는 입력을 적절한 검사 과정을 거치지 않고 JDO(Java Data Objects)API의 SQL 또는 JDOQL 질의문 생성을 위한 문자열로 사용하면, 공격자가 프로그래머가 의도하지 않았던 문자열을 전달함으로써 질의문의 의미를 왜곡시키거나 그 구조를 변경하여 임의의 질의 명령어를 수행할 수 있다.

나. 안전한 코딩기법

JDO 질의문의 생성시에는 상수 문자열만을 사용하고 Query.execute(…) 실행시에는 인자값을 전달하는 방법(Parameterize Query)을 사용한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public class U9102 implements ContactDAO {
3: public List<Contact> listContacts() {
4: PersistenceManager pm = getPersistenceManagerFactory().getPersistenceManager();
5: String query = "select from " + Contact.class.getName();
6: try {
7: Properties props = new Properties();
8: String fileName = "contacts.txt";
9: FileInputStream in = new FileInputStream(fileName);
10: if( in != null ) { props.load(in); }
11: in.close();
12: // 외부로 부터 입력을 받는다
13: String name = props.getProperty("name");
14: if( name != null ) {
15: query += " where name = '" + name + " '" ;
16: }
17: } catch (IOException e) { …… }
18:
19: // 와부 입력값이 JDO 객체의 인자로 사용된다.
20: return (List<Contact>) pm.newQuery(query).execute();
21: }
22: ……

공격자가 외부의 입력(name) 값을 “name'; DELETE FROM MYTABLE; –” 로 주게 되면, 다음과 같은 질의문이 수행되어 테이블이 삭제된다. 


(SELECT col1 FROM MYTABLE WHERE name = 'name' ; DELETE FROM MYTABLE;--')

안전한 코드 예제


1: ……
2: public class S9102 implements ContactDAO {
3: public List<Contact> listContacts() {
4: PersistenceManager pm =
5: getPersistenceManagerFactory().getPersistenceManager();
6: String query = "select from " + Contact.class.getName();
7: String name = "";
8: try {
9: Properties props = new Properties();
10: String fileName = "contacts.txt";
11: FileInputStream in = new FileInputStream(fileName);
12: props.load(in);
13: // 외부로 부터 입력을 받는다.
14: name = props.getProperty("name");
15: // 입력값을 점검한다.
16: if (name == null || " " .equals(name)) return null;
17: query += " where name = ?" ;
18: } catch (IOException e) { …… }
19:
20: javax.jdo.Query q = pm.newQuery(query);
21: // Query API의 인자로 사용한다.
22: return (List<Contact>) q.execute(name);
23: }
24: ……

외부 입력 부분을 ?로 설정하고(Parameterize Query), 실행시에 해당 인자값이 전달되도록 수정함으로써 외부의 입력(name)이 질의문의 구조를 변경시키는 것을 방지할 수 있다.

라. 참고문헌

[1] CWE-89 SQL 삽입 - http://cwe.mitre.org/data/definitions/89.html 
[2] OWASP Top 10 2010 - (OWASP 2010) A1 Injection 
[3] JDO API Documentation 
[4] SANS Top 25 2010 - Insecure Interaction Between Components, RANK 2 CWE-89 ImproperNeutralization of Special Elements used in an SQL Command ('SQL Injection')

4. SQL 삽입공격: Persistence(SQL Injection: Persistence)

가. 정의

J2EE Persistence API를 사용하는 응용프로그램에서 외부의 입력을 아무 검증없이 질의문에 그대로 사용하면, 질의문의 의미를 왜곡시키거나 그 구조를 변경하여 임의의 질의 명령어가 수행될 수 있다.

나. 안전한 코딩기법

외부의 입력이 질의문의 구조를 변경할 수 없는 인자화된 질의문(Parameterize Query)을 사용한다. 즉, 질의문의 생성시 상수 문자열만을 사용하고 javax.persistence.Query.setParameter()메소드를 사용하여 인자값을 설정하는 방법을 사용한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public class U9103 implements ServletContextListener {
3: public List<?> getAllItemsInWildcardCollection() {
4: EntityManager em = getEntityManager();
5: List<U9103> r_type = null;
6: try {
7: Properties props = new Properties();
8: String fileName = "conditions.txt";
9: FileInputStream in = new FileInputStream(fileName);
10: props.load(in);
11:
12: // 외부로 부터 입력을 받는다.
13: String id = props.getProperty(" id" );
14: // 외부 입력 값이 query의 인자로 사용이 된다.
15: Query query =
16: em.createNativeQuery("SELECT OBJECT(i) FROM Item i WHERE
i.itemID > " + id);
17: List<U9103> items = query.getResultList();
18: ……
19: return r_type;
20: }
21: ……

공격자가 외부의 입력(id)의 값으로 “foo'; DELETE FROM MYTABLE; –“을 주게 되면, 다음과 같은 질의문이 실행되어 테이블이 삭제된다. 


(SELECT col1 FROM MYTABLE WHERE name = 'foo' ; DELETE FROM MYTABLE;--')

안전한 코드 예제


1: ……
2: public class S9103 implements ServletContextListener {
3: public List<?> getAllItemsInWildcardCollection() {
4: EntityManager em = getEntityManager();
5: List<S9103> r_type = null;
6: try {
7: Properties props = new Properties();
8: String fileName = "conditions.txt";
9: FileInputStream in = new FileInputStream(fileName);
10: props.load(in);
11:
12: // 외부 입력값을 받는다.
13: String id = props.getProperty("id");
14: // 입력값을 검사한다.
15: if (id == null || "".equals(id)) id = "itemid";
16: // Query문을 작성한다.
17: Query query =
18: em.createNativeQuery("SELECT OBJECT(i) FROM Item i WHERE
i.itemID > :id");
19: query.setParameter("id" , id);
20: List<S9103> items = query.getResultList();
21: ……
22: return r_type;
23: }
24: ……

위의 예제와 같이 인자를 받는 질의문(query)을 생성하고, 인자값을 설정하여 실행하도록 한다. 이를 통해 외부의 입력이 질의문의 구조를 변경시키는 것을 방지할 수 있다.

라. 참고문헌

[1] CWE-89 SQL 삽입 - http://cwe.mitre.org/data/definitions/89.html 
[2] OWASP Top 10 2010 - (OWASP 2010) A1 Injection 
[3] SANS Top 25 2010 - Insecure Interaction Between Components, RANK 2 CWE-89 ImproperNeutralization of Special Elements used in an SQL Command ('SQL Injection')

5. SQL 삽입공격: mybatis Data Map(SQL Injection: mybatis Data Map)

가. 정의

외부에서 입력된 값이 질의어의 인자값으로만 사용되지 않고, 질의 명령어에 연결되는 문자열로 사용되면, 공격자가 의도하지 않았던 문자열을 전달함으로써 질의문의 의미를 왜곡시키거나 그 구조를 변경하여 임의의 데이터베이스 명령어를 수행할 수 있다.

나. 안전한 코딩기법

외부의 입력으로부터 위험한 문자나 의도하지 않았던 입력을 제거하는 코드를 프로그램내에 포함시킨다. mybatis Data Map 파일의 인자를 받는 질의 명령어 정의시에 문자열 삽입 인자($…$)를 사용하지 않는다. 즉 #<인자이름># 형태의 질의문을 사용한다

다. 예제

안전하지 않은 코드 예제


1: <?xml version="1.0" encoding="UTF-8"?>
2: <!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd">
3: <sqlMap namespace="Student">
4: <resultMap id="StudentResult" class="Student">
5: <result column="ID" property="id" />
6: <result column="NAME" property="name" />
7: </resultMap>
8: <select id="listStudents" resultMap="StudentResult">
9: SELECT NUM, NAME
10: FROM STUDENTS
11: ORDER BY NUM
12: </select>
13: <select id="nameStudent" parameterClass="Integer" resultClass="Student">
14: SELECT NUM, NAME
15: FROM STUDENTS
16: WHERE NUM = #num#
17: </select>
18: <!-- dynamic SQL 사용 -->
19: <delete id="delStudent" parameterClass="Student">
20: DELETE STUDENTS
21: WHERE NUM = #num# AND Name = '$name$'
22: </delete>
23: </sqlMap>

위의 예제는 mybatis Data Map에서 사용하는 질의문 설정파일(XML)이다. 정의된 질의문중 delStudent 명령어 선언에서 질의문에 삽입되는 인자들 중 $name$으로 전달되는 문자열 값은 그대로 연결되어 질의문이 만들어진다. 따라서 만약 name의 값으로 ”' OR–') 'x'='x'“을 전달하면 다음과 같은 질의문이 수행되어 테이블의 모든 원소를 삭제하게 된다. 


(DELETE STUDENTS WHERE NUM = #num# and Name = '' OR 'x'='x')

안전한 코드 예제


1: <?xml version="1.0" encoding="UTF-8"?>
2: <!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-2.dtd">
3:
4: <sqlMap namespace="Student">
5: <resultMap id="StudentResult" class="Student">
6: <result column="ID" property="id" />
7: <result column="NAME" property="name" />
8: </resultMap>
9: <select id="listStudents" resultMap="StudentResult">
10: SELECT NUM, NAME
11: FROM STUDENTS
12: ORDER BY NUM
13: </select>
14: <select id="nameStudent" parameterClass="Integer" resultClass="Student">
15: SELECT NUM, NAME
16: FROM STUDENTS
17: WHERE NUM = #num#
18: </select>
19:
20: <!-- static SQL 사용 -->
21: <delete id="delStudent" parameterClass="Student">
22: DELETE STUDENTS
23: WHERE NUM = #num# AND Name = '#name#'
24: </delete>
25: </sqlMap>

Name 인자를 #name# 형태로 받도록 수정한다.

라. 참고 문헌

[1] CWE-89 SQL 삽입 - http://cwe.mitre.org/data/definitions/89.html 
[2] OWASP Top 10 2010 - (OWASP 2010) A1 Injection 
[3] SANS Top 25 2010 - Insecure Interaction Between Components, RANK 2 CWE-89 ImproperNeutralization of Special Elements used in an SQL Command ('SQL Injection')

6. 상대 디렉터리 경로 조작(Relative Path Traversal)

가. 정의

외부의 입력을 통하여 “디렉터리 경로 문자열” 생성이 필요한 경우, 외부 입력에서 경로 조작에 사용될 수 있는 문자를 필터링하지 않으면, 예상 밖의 영역에 대한 경로 문자열이 가능해져 시스템 정보누출, 서비스 장애 등을 유발 시킬 수 있다.

나. 안전한 코딩기법

외부의 입력이 직접 파일이름을 생성하는 사용될 수 없도록 한다. 불가피하게 직접 사용하는 경우, 다른 디렉터리의 파일을 접근할 수 없도록 replaceAll() 등의 메소드를 사용하여 위험 문자열(”,/,\)을 제거하는 필터를 거치도록 한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public void f(Properties request) {
3: ……
4: String name = request.getProperty("filename" );
5: if( name != null ) {
6: File file = new File("/usr/local/tmp/" + name);
7: file.delete();
8: }
9: ……
10: }

외부의 입력(name)이 삭제할 파일의 경로설정에 사용되고 있다. 만일 공격자에 의해 name의 값으로 ../../../rootFile.txt와 같은 값을 전달하면 의도하지 않았던 파일이 삭제되어 시스템에 악영향을 준다.

안전한 코드 예제


1: ……
2: public void f(Properties request) {
3: ……
4: String name = request.getProperty("user");
5: if ( name != null && !"".equals(name) ) {
6: name = name.replaceAll("/" , "" );
7: name = name.replaceAll("\\" , "" );
8: name = name.replaceAll(".", " " );
9: name = name.replaceAll("&" , " ");
10: name = name + "-report" ;
11: File file = new File("/usr/local/tmp/" + name);
12: if (file != null) file.delete();
13: }
14: ……
15: }

외부에서 입력되는 값에 대하여 Null여부를 체크하고, 외부에서 입력되는 파일이름(name)에서 상대경로(/, \\, &, . 등 특수문자)를 설정할 수 없도록 replaceAll를 이용하여 특수문자를 제거한다.

라. 참고 문헌

[1] CWE-23 상대 디렉터리 경로 조작 - http://cwe.mitre.org/data/definitions/23.html 
[2] OWASP Top 10 2010 - (OWASP 2010) A4 Insecure Direct Object Reference 
[3] SANS Top 25 2010 - (SANS 2010) Risky Resource Management, Rank 7 CWE ID 22:Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

7. 절대 디렉터리 경로 조작(Absolute Path Traversal)

가. 정의

외부 입력이 파일 시스템을 조작하는 경로를 직접 제어할 수 있거나 영향을 끼치면 위험하다. 사용자 입력이 파일 시스템 작업에 사용되는 경로를 제어하는 것을 허용하면, 공격자가 응용프로그램에 치명적인 시스템 파일 또는 일반 파일을 접근하거나 변경할 가능성이 존재한다. 즉, 경로 조작을 통해서 공격자가 허용되지 않은 권한을 획득하여, 설정에 관계된 파일을 변경할 수 있거나 실행시킬 수 있다.

나. 안전한 코딩기법

외부의 입력을 통해 파일이름의 생성 및 접근을 허용하지 말고, 외부 입력에 따라 접근이 허용된 파일의 리스트에서 선택하도록 프로그램을 작성하는 것이 바람직하다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public void f(Properties cfg) throws IOException {
3: FileInputStream fis = new FileInputStream(cfg.getProperty("subject"));
4: byte[] arr = new byte[30];
5: fis.read(arr);
6: System.out.println(arr);
7: ……
8: }

외부의 입력(fis)으로 부터 직접 파일을 생성하게 되는 경우, 임의의 파일이름을 입력 받을 수 있도록 되어 있어, 다른 파일에 접근이 가능해져 의도하지 않은 정보가 노출될 수 있다.

안전한 코드 예제


1: ……
2: public void f(Properties cfg) throws IOException {
3: FileInputStream fis;
4: String subject = cfg.getProperty("subject");
5:
6: if (subject.equals("math" ))
7: fis = new FileInputStream("math");
8: else if (subject.equals("physics"))
9: fis = new FileInputStream("physics" );
10: else if (subject.equals("chemistry" ))
11: fis = new FileInputStream("chemistry");
12: else
13: fis = new FileInputStream("default");
14:
15: byte[] arr = new byte[30];
16: fis.read(arr);
17: System.out.println(arr);
18: ……
19: }

위의 예제와 같이 접근이 허용된 파일의 리스트에서 외부 입력에 따라 파일을 선택하도록 프로그램을 작성하는 것이 바람직하다.

라. 참고 문헌

[1] CWE-36 절대 디렉터리 경로 조작 - http://cwe.mitre.org/data/definitions/36.html 
[2] OWASP Top 10 2010 - (OWASP 2010) A4 Insecure Direct Object Reference 
[3] SANS Top 25 2010 - Risky Resource Management, Rank 7 CWE ID 22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

8. 운영체제 명령어 삽입(Improper Neutralization of Special Elements Used in an OS Command (OS Command Injection))

가. 정의

외부 입력이 시스템 명령어 실행 인수로 적절한 처리 없이 사용되면 위험하다. 외부 입력 문자열은 신뢰할 수 없기 때문에 미리 정당한 인자값의 배열을 만든 후 적절한 인자값을 선택하는 형태로 사용해야 한다. 그렇지 않으면, 공격자가 원하는 명령어를 실행시킬 수 있다.

나. 안전한 코딩기법

외부에서 전달되는 값은 바로 시스템 내부 명령어의 생성에 사용되지 않아야 한다. 외부 입력에 따른 명령어 생성 또는 선택이 필요한 경우에는 명령어 생성에 필요한 값들을 미리 지정해 놓고 외부의 입력에 따라 선택하여 사용하는 것이 안전하다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public void f() throws IOException {
3: Properties props = new Properties();
4: String fileName = "file_list";
5: FileInputStream in = new FileInputStream(fileName);
6: props.load(in);
7: String version = props.getProperty("dir_type" );
8: String cmd = new String("cmd.exe /K \"rmanDB.bat \"");
9: Runtime.getRuntime().exec(cmd + " c:\\prog_cmd\\" + version);
10: ……
11: }

위 예제는 cmd.exe 명령어를 사용하여 rmanDB.bat 배치 명령어를 수행하며, 외부에서 전달되는 dir_type 값이 manDB.bat의 인자값으로서 명령어 스트링의 생성에 사용되고 있다. 
만약 외부의 공격자가 의도하지 되지 않은 문자열을 전달할 시, dir_type이 의도했던 인자값이 아닐 경우, 비정상적인 업무를 수행할 수 있다.

안전한 코드 예제


1: ……
2: public void f() throws IOException {
3: Properties props = new Properties();
4: String fileName = "file_list";
5: FileInputStream in = new FileInputStream(fileName);
6: props.load(in);
7: String version[] = {"1.0" , "1.01" , "1.11" , "1.4" };
8: int versionSelection = Integer.parseInt(props.getProperty("version" ));
9: String cmd = new String("cmd.exe /K \"rmanDB.bat \"");
10: String vs = "";
11:
12: // 외부 입력값에 따라 지정된 목록에서 값을 선택한다.
13: if (versionSelection == 0)
14: vs = version[0];
15: else if (versionSelection == 1)
16: vs = version[1];
17: else if (versionSelection == 2)
18: vs = version[2];
19: else if (versionSelection == 3)
20: vs = version[3];
21: else
22: vs = version[3];
23: Runtime.getRuntime().exec(cmd + " c:\\prog_cmd\\" + vs);
24: ……
25: }

위와 같이 미리 정당한 인자값의 배열을 만들어 놓고, 외부의 입력에 따라 적절한 인자값을 선택하도록 하여, 외부의 부적절한 입력이 명령어로 사용될 가능성을 배제하여야 한다.

라. 참고 문헌

[1] CWE-78 운영체제 명령어 삽입 - http://cwe.mitre.org/data/definitions/78.html 
[2] OWASP Top 10 2010 - (OWASP 2010) A1 Injection 
[3] SANS, Frank Kim. “Top 25 Series - Rank 9 - OS Command Injection”. 
[4] SANS Top 25 2010 - Insecure Interaction Between Components, RANK 9 CWE-78: ImproperNeutralization of Special Elements used in an OS Command ('OS Command Injection')

9. LDAP 삽입(LDAP Injection)

가. 정의

공격자가 외부 입력을 통해서 의도하지 않은 LDAP 명령어를 수행할 수 있다. 즉 웹 애플리케이션이 사용자가 제공한 입력을 올바르게 처리하지 못하면, 공격자가 LDAP 명령문의 구성을 바꿀 수 있으며, 이로 인해 프로세스가 명령을 실행한 컴포넌트와 동일한 Authentication을 가지고 동작하게 된다.

나. 안전한 코딩기법

외부의 입력이 LDAP 필터 문자열로 사용될 경우, 가능한 입력의 집합(white list) 또는 위험한 입력 문자열의 집합(black list의 예로는 = + < > # ; \ 등이 있음)을 설정하여, 임의의 외부의 입력이 필터 생성에 사용되지 않도록 관리한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public void f() {
3: Hashtable env = new Hashtable();
4: env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
5: env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=rootDir");
6: try {
7: javax.naming.directory.DirContext ctx = new InitialDirContext(env);
8: // 프로퍼티를 만들고 외부 파일을 로드한다.
9: Properties props = new Properties();
10: String fileName = "ldap.properties";
11: FileInputStream in = new FileInputStream(fileName);
12: props.load(in);
13: // LDAP Search를 하기 위해 name을 읽는다
14: String name = props.getProperty("name" );
15: String filter = "(name =" + name + ")";
16: // LDAP search가 name값에 대한 여과없이 그대로 통과되어 검색이 되어진다.
17: NamingEnumeration answer =
ctx.search("ou=NewHires" , filter, new SearchControls());
18: printSearchEnumeration(answer);
19: ctx.close();
20: } catch (NamingException e) { …… }
21: ……

위 예제는 외부의 입력(name)이 검색을 위한 필터 문자열의 생성에 사용되고 있다. 이 경우 name 변수의 값으로 “*”을 전달할 경우 필터 문자열은 ”(name=*)“가 되어 항상 참이 되며 이는 의도하지 않은 동작일 수 있다.

안전한 코드 예제


1: ……
2: public void f() {
3: Hashtable env = new Hashtable();
4: env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
5: env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=rootDir");
6: try {
7: javax.naming.directory.DirContext ctx = new InitialDirContext(env);
8: Properties props = new Properties();
9: String fileName = "ldap.properties";
10: FileInputStream in = new FileInputStream(fileName);
11:
12: if (in == null || in.available() <= 0) return;
13: props.load(in);
14:
15: if (props == null || props.isEmpty()) return;
16: String name = props.getProperty("name");
17: if (name == null || "".equals(name)) return;
18: // 읽어들인 name에 대해서 ‘*’ 문자열을 제거한다.
19: String filter = "(name =" + name.replaceAll("\\*", " " ) + ")";
20: NamingEnumeration answer =
21: ctx.search("ou=NewHires", filter, new SearchControls());
22: printSearchEnumeration(answer);
23: ctx.close();
24: } catch (NamingException e) { …… }
25: ……

검색을 위한 필터 문자열로 사용되는 외부의 입력에서 위험한 문자열을 제거하여 위험성을 부분적으로 감소시킬 수 있다.

라. 참고 문헌

[1] CWE-90 LDAP 삽입 - http://cwe.mitre.org/data/definitions/90.html 
[2] OWASP Top 10 2010 - (OWASP 2010) A1 - Injection 
[3] SPI Dynamics. “Web Applications and LDAP Injection”. 
[4] SANS Top 25 2009 - (SANS 2009) Insecure Interaction - CWE ID 116 Improper Encoding or Escaping of Output

10. LDAP 처리(LDAP Manipulation)

가. 정의

LDAP 질의문이나 결과로 외부 입력이 부분적으로 적절한 처리없이 사용되면 LDAP 질의문이 실행될 때 공격자는 LDAP 질의문의 내용을 마음대로 변경할 수 있다.

나. 안전한 코딩기법

외부 입력에 대한 적절한 유효성 검증 후 사용해야 하며, LDAP 사용시 질의문을 제한하여 허용된 레코드만을 접근하도록 하는 접근 제어 기능을 사용해야 한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: try {
3: ……
4: // 외부로 부터 입력을 받는다.
5: String name = props.getProperty(“ldap.properties" );
6: // 입력값에 대한 BasicAttribute를 생성한다.
7: BasicAttribute attr = new BasicAttribute("name" , name);
8: // 외부 입력값이 LDAP search의 인자로 사용이 된다.
9: NamingEnumeration answer =
10: ctx.search("ou=NewHires", attr.getID(), new SearchControls());
11: printSearchEnumeration(answer);
12: ctx.close();
13: } catch (NamingException e) { …… }
14: }
15:
16: public void printSearchEnumeration(NamingEnumeration value) {
17: try {
18: while (value.hasMore()) {
19: SearchResult sr = (SearchResult) value.next();
20: System.out.println(">>>" + sr.getName() + "\n" + sr.getAttributes());
21: }
22: } catch (NamingException e) { …… }
23: ……

위의 예제는 외부의 입력(name)이 검색을 위한 base 문자열의 생성에 사용되고 있다. 이경우 임의의 루트 디렉터리를 지정하여 정보에 접근할 수 있으며, 적절한 접근제어가 동반되지 않을 경우 정보 누출이 발생할 수 있다.

안전한 코드 예제


1: ……
2: try {
3: ……
4: // 외부로 부터 입력값을 받는다.
5: String name = props.getProperty("name");
6: // 입력값에 대한 검사를 한다.
7: if (name == null || "".equals(name)) return;
8: String filter = "(name =" + name.replaceAll("\\*", " " ) + ")";
9:
10: // 검증된 입력값을 LDAP search 인자로 사용한다.
11: NamingEnumeration answer =
12: ctx.search("ou=NewHires", filter, new SearchControls());
13: printSearchEnumeration(answer);
14: ctx.close();
15: } catch (NamingException e) { …… }
16: }
17:
18: public void printSearchEnumeration(NamingEnumeration value) {
19: try {
20: while (value.hasMore()) {
21: SearchResult sr = (SearchResult) value.next();
22: System.out.println(">>>" + sr.getName() + "\n" + sr.getAttributes());
23: }
24: } catch (NamingException e) { …… }
25: ……

외부 입력에 대한 적절한 유효성 검증 후 사용해야 하며, LDAP 사용시 질의문을 제한하여 허용된 레코드만을 접근하도록 하는 접근 제어 기능을 사용해야 한다.

라. 참고 문헌

[1] CWE-639 사용자 제어 키를 이용한 인증 - http://cwe.mitre.org/data/definitions/639.html 
CWE-90 LDAP 삽입 - http://cwe.mitre.org/data/definitions/90.html 
CWE-116 출력값의 부적절한 인코딩 또는 이스케이핑 - http://cwe.mitre.org/data/definitions/116.html 
[2] OWASP Top 10 2010 - (OWASP 2010) A4 Insecure Direct Object Reference 
[3] SANS Top 25 2009 - (SANS 2009) Insecure Interaction - CWE ID 116 Improper Encoding or Escaping of Output

11. 자원 삽입(Resource Injection)

가. 정의

외부의 신뢰할 수 없는 입력이 적절한 검사과정을 거치지 않고 자원(resource) 식별자로 사용될 경우 부적절한 자원 접근이 일어날 수 있다.

나. 안전한 코딩기법

외부의 입력을 아무 검증없이 자원 식별자로 사용하지 말고, 외부의 입력에 따라 적합한 리스트(white list)에서 선택되도록 작성한다. 만일, 외부의 입력이 파일명이면 경로 순회를 수행하는 위험한 문자를 제거한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public void f() throws IOException {
3: int def = 1000;
4: ServerSocket serverSocket;
5: Properties props = new Properties();
6: String fileName = "file_list";
7: FileInputStream in = new FileInputStream(fileName);
8: props.load(in);
9:
10: // 외부에서 입력한 데이터를 받는다.
11: String service = props.getProperty("Service No" );
12: int port = Integer.parseInt(service);
13:
14: // 외부에서 입력받은 값으로 소켓을 생성한다.
15: if (port != 0)
16: serverSocket = new ServerSocket(port + 3000);
17: else
18: serverSocket = new ServerSocket(def + 3000);
19: ……
20: }
21: …

위의 예제는 외부의 입력(service)을 소켓 번호로 그대로 사용하고 있다. 만일, 공격자가“Service No” 의 값으로 “-2920” 과 같은 값을 지정하면 기존의 80 포트에서 구동되는 서비스와 충돌되어 에러를 야기할 수 있다.

안전한 코드 예제


1: ……
2: public void f() throws IOException {
3: ServerSocket serverSocket;
4: Properties props = new Properties();
5: String fileName = "file_list";
6: FileInputStream in = new FileInputStream(fileName);
7: String service = "";
8:
9: if (in != null && in.available() > 0) {
10: props.load(in);
11: // 외부로부터 데이터를 입력받는다.
12: service = props.getProperty("Service No");
13: }
14: // 외부의 입력을 기본적인 내용 검사를 한다.
15: if ("".equals(service)) service = "8080";
16:
17: int port = Integer.parseInt(service);
18: // 외부 입력에서 포트번호를 검사한 후 리스트에서 적합한 값을 할당한다.
19: switch (port) {
20: case 1:
21: port = 3001; break;
22: case 2:
23: port = 3002; break;
24: case 3:
25: port = 3003; break;
26: default:
27: port = 3000;
28: }
29: // 서버소켓에 검사완료된 포트를 할당한다.
30: serverSocket = new ServerSocket(port);
31: ……
32: }
33: ……

외부로부터 소켓 번호와 같은 자원을 직접 받는 것은 바람직하지 않다. 꼭 필요한 경우 가능한 리스트를 설정하고, 해당 범위 내에서 할당되도록 작성한다.

라. 참고 문헌

[1] CWE-99 자원 삽입 - http://cwe.mitre.org/data/definitions/99.html

12. HTTP 응답 분할(Failure to Sanitize CRLF Sequences in HTTP Headers ('HTTP Response Splitting'))

가. 정의

HTTP 요청에 들어 있는 인자값이 HTTP 응답헤더에 포함되어 사용자에게 다시 전달되는 경우 입력값에 CR(Carriage Return)이나 LF(Line Feed)와 같은 개행문자가 존재하면 HTTP 응답이 2개 이상으로 분리될 수 있다. 이 경우 공격자는 개행문자를 이용하여 첫번째 응답을 종료시키고 두 번째 응답에 악의적인 코드를 주입할 수 있게 되어 공격자는 두 번째 응답을 이용해서 XSS 및 캐시 훼손(cache poisoning) 공격과 같은 것을 시도할 수 있다.

나. 안전한 코딩기법

외부에서 입력된 인자값을 사용하여 HTTP 응답헤더(Set Cookie 등)에 포함시킬 경우 CR,LF등이 제거하거나 적절한 인코딩 기법을 사용하여 변환한다.

다. 예제

안전하지 않는 코드 예제


1: public class U113 extends HttpServlet {
2: public void doPost(HttpServletRequest request, HttpServletResponse response)
3: throws IOException, ServletException {
4: response.setContentType("text/html");
5: // 사용자의 입력정보를 받아서 쿠키를 생성한다.
6: String author = request.getParameter("authorName" );
7: Cookie cookie = new Cookie("replidedAuthor" , author);
8: cookie.setMaxAge(1000);
9: // cookie.setSecure(true); // HTTP로 서비스하는 경우 쿠키 값 설정 안됨(위험)
10: // HTTPS 서비스만 제공하는 경우 사용
11: ...
12: // 생성된 쿠키를 브라우저에 전송해 저장하도록 한다.
13: response.addCookie(cookie);
14: RequestDispatcher frd = request.getRequestDispatcher("cookieTest.jsp");
15: frd.forward(request, response);
16: }
17: }

위 예제는 외부의 입력값을 사용하여 반환되는 쿠키의 값을 설정하고 있다. 그런데, 공격자가 “Wiley Hacker\r\nHTTP/1.1 200 OK\r\n”를 authorName의 값으로 설정할 경우, 아래의 예와 같이 의도하지 않은 두개의 페이지가 전달된다. 또한 두번째 응답 페이지는 공격자가 마음대로 수정 가능하다. 


(예 : HTTP/1.1 200 OK...Set-Cookie: author=Wiley Hacker HTTP/1.1 200 OK...)

안전한 코드 예제


1: public class S113 extends HttpServlet {
2: public void doPost(HttpServletRequest request, HttpServletResponse response)
3: throws IOException, ServletException {
4: response.setContentType("text/html");
5:
6: // 사용자 정보를 읽어온다.
7: String author = request.getParameter("authorName");
8: if (author == null || "".equals(author)) return;
9:
10: // 헤더값이 두개로 나뉘어지는 것을 방지하기 위해 외부에서 입력되는 \n과 \r
등을 제거한다.
11: String filtered_author = author.replaceAll("\r" , " ").replaceAll("\n" , " ");
12: Cookie cookie = new Cookie("replidedAuthor", filtered_author);
13: cookie.setMaxAge(1000);
14: cookie.setSecure(true);
15:
16: // 생성된 쿠키를 브라우저에 전송해 저장하도록 한다.
17: response.addCookie(cookie);
18: RequestDispatcher frd = request.getRequestDispatcher("cookieTest.jsp");
19: frd.forward(request, response);
20: }
21: }

외부에서 입력되는 값에 대하여 Null여부를 체크하고, 두개로 나누어 지는 것을 방지하기 위해 relpaceAll을 이용하여 개행문자(\r, \n)을 제거하여 헤더값이 나누어지는 것을 방지한다.

라. 참고 문헌

[1] CWE-113 HTTP 응답 분할 - http://cwe.mitre.org/data/definitions/113.html 
[2] OWASP Top 10 2004 A1 Unvalidated Input 
[3] OWASP Top 10 2007 A2 Injection Flaws 
[4] Web Application Security Consortium 24 + 2 HTTP Response Splitting

13. 시스템 또는 구성 설정의 외부 제어(External Control of System or Configuration Setting)

가. 정의

시스템 설정이나 구성요소를 외부에서 제어할 수 있으면 예상치 못한 결과(예: 서비스 중단)를 초래하거나 악용될 가능성이 있다.

나. 안전한 코딩기법

외부의 입력을 Connection.setCatalog() 메소드의 인자값을 생성하는데 사용하지 않도록 한다. 불가피하게 사용해야 한다면, 외부의 입력을 화이트 리스트 방식으로 검사한 후 사용한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public void f() {
3: try {
4: InitialContext ctx = new InitialContext();
5: DataSource datasource = (DataSource) ctx.lookup("jdbc:ocl:orcl");
6: Connection con = datasource.getConnection();
7: Properties props = new Properties();
8: String fileName = "file.properties";
9: FileInputStream in = new FileInputStream(fileName);
10: props.load(in);
11:
12: // catalog정보는 외부로부터 유입되는 정보
13: String catalog = props.getProperty("catalog");
14: // catalog정보를 DB Connection을 위해서 해당 값을 체크하지 않고, DB 카탈
로그 정보에 지정함
15: con.setCatalog(catalog);
16: con.close();
17: } catch (SQLException ex) {
18: System.err.println("SQLException Occured");
19: } catch (NamingException e) {
20: System.err.println("NamingException Occured");
21: } catch (FileNotFoundException e) {
22: System.err.println("FileNotFoundException Occured");
23: } catch (IOException e) {
24: System.err.println("IOException Occured");
25: }
26: }
27: ……

외부의 입력(catalog)이 JDBC의 활성화된 카탈로그를 설정하는데 사용되고 있다. 이때 존재하지 않는 카탈로그나 권한이 없는 카탈로그 이름이 전달되면 예외상황을 발생할 수 있다.

안전한 코드 예제


1: ……
2: public void f() {
3: try {
4: // caltalog 값으로 c1과 c2를 사용할 경우
5: InitialContext ctx = new InitialContext();
6: DataSource datasource = (DataSource) ctx.lookup("jdbc:ocl:orcl");
7: Connection con = datasource.getConnection();
8:
9: Properties props = new Properties();
10: String fileName= "file.properties";
11: String catalog;
12:
13: FileInputStream in = new FileInputStream(fileName);
14: if (in != null && in.available() > 0) {
15: props.load(in);
16:
17: if (props == null || props.isEmpty()) catalog = "c1";
18: else
19: catalog = props.getProperty("catalog");
20: } else
21: catalog = "c1";
22:
23: // 외부 유입 변수(catalog)에 대해서 값을 반드시 체크하고 걸러야 한다.
24: if ("c1" .equals(catalog))
25: con.setCatalog("c1" );
26: else
27: con.setCatalog("c2" );
28: con.close();
29: } catch (SQLException ex) {
30: System.err.println("SQLException Occured");
31: } catch (NamingException e) {
32: System.err.println("NamingException Occured");
33: } catch (FileNotFoundException e) {
34: System.err.println("FileNotFoundException Occured");
35: } catch (IOException e) {
36: System.err.println("IOException Occured");
37: }
38: }

외부의 입력값에 따라 카탈로그 이름이 바뀌어야 할 경우에는 해당 문자열을 직접 사용하지 말고, 미리 정의된 적절한 카탈로그 이름 중에 선택하여 사용한다.

라. 참고 문헌

[1] CWE-15 시스템 또는 구성 설정의 외부 제어 - http://cwe.mitre.org/data/definitions/15.html

14. 크로스 사이트 스크립트 공격 취약점: DOM (Improper Neutralization of Script-Related HTML Tags in a Web Page (DOM))

가. 정의

외부에서 입력되는 스크립트 문자열이 웹페이지 생성에 사용되면 생성된 웹페이지를 열람하는 사용자에게 피해를 입힐 수 있다.

나. 안전한 코딩기법

JSP의 document.write() 메소드와 같이 JSP의 DOM 객체 출력을 수행하는 메소드의 인자 값으로 외부의 입력을 사용할 경우 위험한 문자를 제거하는 과정이 수행되어야 한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: <%
3: // 외부로 부터 입력을 받는다.
4: String name = request.getParameter("name");
5: %>
6: <SCRIPT language="javascript">
7: // 외부의 입력을 그대로 출력한다.
8: document.write("name:" + <%=name%> );

request.getParameter()에서 전달된 외부의 입력(name)이 document.write()의 인자값 생성에 그대로 사용되었다.

안전한 코드 예제


1: ……
2: <%
3: // 외부의 입력을 받는다.
4: String name = request.getParameter("name");
5: // 입력값에 대한 유효성 검사를 한다.
6: if ( name != null ) {
7: name = name.replaceAll("<","&lt;" );
8: name = name.replaceAll(">","&gt" );
9: } else { return; }
10: %>
11: <SCRIPT language="javascript">
12: // 입력값이 출력된다.
13: document.write("name:" + <%=name%> );

외부의 입력(name)으로부터 “<”와 ”>“같이 HTML에서 스크립트 생성에 사용되는 모든 문자열을 ”&lt;”와 “&gt;“로 변경한다.

라. 참고 문헌

[1] CWE-79 웹 페이지 구조 보존 실패 - http://cwe.mitre.org/data/definitions/79.html 
CWE-80 크로스 사이트 스크립트 공격 취약점(XSS) - http://cwe.mitre.org/data/definitions/80.html 
[2] OWASP Top 10 2010 - (OWASP 2010) A2 Cross Site Scripting (XSS) 
[3] SANS Top 25 2010 - (SANS 2010) Insecure Interaction - CWE ID 079 ImproperNeutralization of Input During Web Page Generation ('Cross-site Scripting')

15. 동적으로 생성되어 수행되는 명령어 삽입(Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection'))

가. 정의

신뢰할 수 없는 외부입력이 적절한 검사과정을 거치지 않고 동적으로 수행되는 스크립트 또는 프로그램 명령어 문자열의 생성에 사용될 경우 의도했던 형태의 입력만 사용되도록 적절히 필터링해야 한다. 그렇지 않으면, 외부의 임의의 입력이 명령어로 사용되어 공격자는 원하는 임의의 작업을 수행할 수 있다.

나. 안전한 코딩기법

외부의 입력이 eval() 함수의 인자로 사용될 경우 외부에서 입력되는 JavaScript가 수행되지 않도록 위험문자를 제거해야 한다.

다. 예제

안전하지 않는 코드 예제


1: <%@page import="org.owasp.esapi.*"%>
2: <%@page contentType="text/html" pageEncoding="UTF-8"%>
3: <html>
4: <head>
5: <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
6: </head>
7: <body>
8: <h1>Eval 취약점 샘플</h1>
9: <%
10: String evalParam = request.getparameter("eval" );
11: ……
12: %>
13: <script>
14: eval(<%=evalParam%>);
15: </script>
16: </body>
17: </html>

외부 입력(evalParam)을 eval() 함수의 인자로 사용하고 있다. 만약 외부 입력에 javascript로 된 코드가 있다면 이 코드가 eval()에 의해서 수행이 된다.

안전한 코드 예제


1: <%@page import="org.owasp.esapi.*"%>
2: <%@page contentType="text/html" pageEncoding="UTF-8"%>
3: <html>
4: <head>
5: <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
6: </head>
7: <body>
8: <h1>Eval 취약점 샘플</h1>
9: <%
10: // 외부의 입력값을 받는다.
11: String evalParam = request.getparameter("eval");
12: // 입력값에 대한 유효성을 체크한다.
13: if ( evalParam != null ) {
14: evalParam = evalParam.replaceAll("<","&lt;" );
15: evalParam = evalParam.replaceAll(">","&gt;");
16: evalParam = evalParam.replaceAll("&" ,"&amp;");
17: evalParam = evalParam.replaceAll("(","&#40;" );
18: evalParam = evalParam.replaceAll(")","&#41;" );
19: evalParam = evalParam.replaceAll("\"" ,"&quot;" );
20: evalParam = evalParam.replaceAll("\'" ,"&apos;");
21: }
22: ……
23: %>
24: <script>
25: eval(<%=evalParam%>);
18: </script>
19: </body>
20: </html>

위와 같이 스크립트를 작성하는데 필요한 문자들(예: <, >, &, \ 등등)을 변경함으로써 외부 입력 코드의 수행을 방지할 수 있다.

라. 참고 문헌

[1] CWE-95 동적으로 생성되어 수행되는 명령어 삽입 - http://cwe.mitre.org/data/definitions/95.html 
[2] OWASP Top Ten 2007 Category A3 - Malicious File Execution 
[3] SANS Top 25 2009 - (SANS 2009) Insecure Interaction - CWE ID 116 Improper Encoding or Escaping of Outpu

16. 프로세스 제어(Process Control)

가. 정의

신뢰되지 않은 소스나 신뢰되지 않은 환경으로부터 라이브러리를 적재하거나 명령을 실행하면, 악의적인 코드가 실행될 수 있다.

나. 안전한 코딩기법

프로그램 내에서 라이브러리 적재시 절대경로를 사용한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public void loadLibrary() throws SecurityException, UnsatisfiedLinkError, NullPointerException
{
3: // 외부 라이브러리를 호출 시 절대 경로가 들어 있지 않다.
4: Runtime.getRuntime().loadLibrary(" libraryName");
5: }
6: ……

위의 예제는 라이브러리명을 지정할 때 절대 경로를 사용하지 않고 있어서 공격자가 환경변수를 조작하면 다른 라이브러리가 적재될 수 있다.

안전한 코드 예제


1: ……
2: public void loadLibrary() throws SecurityException, UnsatisfiedLinkError, NullPointerException
{
3: // 외부 라이브러리 호출 시 절대 경로를 지정한다.
4: Runtime.getRuntime().loadLibrary("/usr/lib/libraryName" );
5: }
6: ……

절대 경로를 지정하면 환경 변수에 의하여 라이브러리가 변경되는 것을 방지할 수 있다.

라. 참고 문헌

[1] CWE-114 프로세스 제어 - http://cwe.mitre.org/data/definitions/114.html

17. 정수 오버플로우(Integer Overflow)

가. 정의

정수형 변수의 오버플로우는 정수값이 증가하면서, Java에서 허용된 가장 큰 값보다 더 커져서 실제 저장되는 값은 의도하지 않게 아주 작은 수이거나 음수가 될 수 있다. 이러한상황을 검사하지 않고 그 값을 순환문의 조건이나 메모리 할당, 메모리 복사 등에 쓰거나, 그 값에 근거해서 보안 관련 결정을 하면 취약점을 야기할 수 있다.

나. 안전한 코딩기법

동적 메모리 할당을 위해서 사용되는 변수가 이전 처리 과정에서 오버플로우에 의해서 음수값으로 변환될 수 있으므로 미리 변수의 값 범위를 검사한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public static void main(String[] args) {
3: int size = new Integer(args[0]).intValue();
4: size += new Integer(args[1]).intValue();
5: MyClass[] data = new MyClass[size];
6: ……
7:

위의 예제는 외부의 입력(args[0], args[1])을 이용하여 동적으로 계산한 값을 배열의 크기(size)를 결정하는데 사용하고 있다. 만일 외부 입력으로부터 계산된 값(size)이 오버플로우에 의해 음수값이 되면 배열의 크기가 음수가 되어 코드에 문제 발생할 수 있다.

안전한 코드 예제


1: ……
2: public static void main(String[] args) {
3: int size = new Integer(args[0]).intValue();
4: size += new Integer(args[1]).intValue();
5: // 배열의 크기 값이 음수값이 아닌지 검사한다.
6: if (size < 0) return ;
7: MyClass[ ] data = new MyClass[size];
8: ……

동적 메모리 할당을 위해 크기를 사용하는 경우 그 값이 음수가 아닌지 검사하는 문장이 필요하다.

라. 참고 문헌

[1] CWE-190 정수 오버플로우 - http://cwe.mitre.org/data/definitions/190.html

18. 무제한 파일 업로드(Unrestricted Upload of File with Dangerous Type)

가. 정의

운영 환경 내에서 자동으로 처리될 수 있는 위험한 유형의 파일을 공격자가 업로드하거나 전송할 수 있게 허용하면 취약점을 야기할 수 있다.

나. 안전한 코딩기법

업로드하는 파일 타입과 크기를 제한하고, 업로드 디렉터리를 웹서버의 다큐먼트 외부에 설정한다. 
화이트리스트 방식으로 허용된 확장자만 업로드되도록 하고, 확장자도 대소문자 구분 없이 처리하도록 한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public void upload(HttpServletRequest request) throws ServletException {
3: MultipartHttpServletRequest mRequest = (MultipartHttpServletRequest) request;
4: String next = (String) mRequest.getFileNames().next();
5: MultipartFile file = mRequest.getFile(next);
6:
7: // MultipartFile로부터 file을 얻음
8: String fileName = file.getOriginalFilename();
9:
10: // upload 파일에 대한 확장자, 크기의 유효성 체크를 하지 않음
11: File uploadDir = new File("/app/webapp/data/upload/notice");
12: String uploadFilePath = uploadDir.getAbsolutePath()+"/" + fileName;
13:
14: /* 이하 file upload 루틴 */
15: ……

업로드할 파일에 대한 유효성을 검사하지 않으면, 위험한 유형의 파일을 공격자가 업로드하거나 전송할 수 있다.

안전한 코드 예제


1: ……
2: public void upload(HttpServletRequest request) throws ServletException {
3: MultipartHttpServletRequest mRequest = (MultipartHttpServletRequest) request;
4: String 
                                     
                    				  
                    				  
                    				    
									    

 

about author

PHRASE

Level 60  머나먼나라

잠을 자야 꿈을 꾸지 , 어떤 결과를 얻으려면 먼저 그에 필요한 조건을 갖추어 놓아야 한다는 뜻.

댓글 ( 4)

댓글 남기기

작성

자바 목록    more