자바

JAVA 보안 개발 가이드 5

 

5. 코드 정확성: Thread.run() 호출(Code Correctness: Call to Thread.run())

가. 정의

프로그램에서 스레드의 start() 대신에 run()을 호출하면 스레드가 생성되지 않고, 해당 un() 함수를 직접 호출하여 해당 run() 함수의 종료를 대기하게 된다. 즉, 프로그래머는 새로운 스레드를 시작시키려고 했지만, start() 대신에 run()을 호출함으로써 호출자의 스레드에서 run() 메소드를 실행하게 된다.

나. 안전한 코딩기법

스레드의 run() 대신에 start()를 수행하도록 한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: protected void cwe_572() {
3: Thread thr = new PrintThread();
4: // 스레드 객체의 run() 메소드를 직접 호출하는 것은 대부분 버그이다.
5: thr.run();
6: } ……
7: }
8: class PrintThread extends Thread {
9: public void run() { System.out.println("CWE 572 TEST"); }
10: }

start() 대신에 run() 메소드를 사용하고 있다.

안전한 코드 예제


1: ……
2: protected void cwe_572() {
3: Thread thr = new PrintThread();
4: // 새로운 스레드를 시작시킨다.
5: thr.start();
6: } ……
7: }
8: class PrintThread extends Thread {
9: public void run() { System.out.println("CWE 572 TEST"); }
10: }

스레드의 start() 메소드를 사용한다.

라. 참고 문헌

[1] CWE-572 코드 정확성: Thread.run() 호출 - http://cwe.mitre.org/data/definitions/572.html

6. 코드 정확성: 동기화된 메소드를 비동기화된 메소드로 재정의 (Code Correctness: Non-Synchronized Method Overrides Synchronized Method)

가. 정의

클래스를 상속받아 사용하는 경우, 상위 클래스에서 동기화된(synchronized) 메소드는 하위 클래스에서 재정의(override)를 하지 않거나, 재정의해야 하는 경우 기존과 동일하게 동기화된(synchronized) 메소드로 정의해야 한다.

나. 안전한 코딩기법

하위 클래스에서 동기화된(synchronized) 메소드를 재정의해야 하는 경우, 상위 클래스와 동일하게 synchronized 메소드로 재정의해야 한다.

다. 예제

안전하지 않는 코드 예제


1: public class U9627 {
2: public synchronized void synchronizedMethod() {
3: for (int i=0; i<10; i++) System.out.print(i);
4: }	
5: ……
6: }
7:
8: public class Foo extends U9627 {
9: //동기화된 메소드로 정의하지 않았다.
10: public void synchronizedMethod() {
11: for (int i=0; i<20; i++) System.out.print(i);
12: }
13: }

상위 클래스에서 동기화된(synchronized) 메소드를 하위 클래스에서 비동기화된 메소드로 재정의(override)하면 안 된다

안전한 코드 예제


1: public class S9627 {
2: public synchronized void synchronizedMethod() {
3: for (int i=0; i<10; i++) System.out.print(i);
4: }
5: ……
6: }
7:
8: public class Foo extends S9627 {
9: public synchronized void synchronizedMethod() {
10: for (int i=0; i<20; i++) System.out.print(i);
11: }
12: }

동기화된(synchronized) 메소드는 재정의하지 않거나 재정의하면 동기화된(synchronized) 메소드로 제정의해야 한다.

라. 참고 문헌

[1] CWE-665 부적절한 초기화 - http://cwe.mitre.org/data/definitions/665.html 
[2] Sun Microsystems, Inc. Bug ID: 4294756 Javac should warn if synchronized method is overridden with a non synchronized

7. 무한 자원 할당(Allocation of Resources Without Limits or Throttling)

가. 정의

프로그램이 자원을 사용 후 해제하지 않거나, 한 사용자당 서비스할 수 있는 자원의 양을 제한하지 않고, 서비스 요청마다 요구하는 자원을 할당한다.

나. 안전한 코딩기법

프로그램에서 자원을 오픈하여 사용하고 난 후, 반드시 자원을 해제한다. 
사용자가 사용할 수 있는 자원의 사이즈를 제한한다. 
※ 사용자가 접근할 수 있는 자원의 양을 제한한다. 특히 제한된 자원을 효율적으로 사용하기 위해서 Pool(Thread Pool, Connection Pool 등)을 사용한다.

다. 예제

안전하지 않는 코드 예제


1: Connection conn = null;
2: PreparedStatement pstmt = null;
3: try {
4: conn=getConnection();
5: ...
6: pstmt = conn.prepareStatement("SELECT * FROM employees
7: where name=?");
8: ...
9: conn.close();
10: pstmt.close();
11: }catch (SQLException ex) {...}

close()문을 만나기 전에 예외가 일어나면, open된 자원은 dangling resource로 메모리에 존재한다. 즉 참조를 잃어버렸기 때문에 재사용은 불가하다.

안전한 코드 예제


1: Connection conn = null;
2: PreparedStatement pstmt = null;
3: try {
4: conn=getConnection();
5: ...
6: pstmt = conn.prepareStatement("SELECT * FROM employees
7: where name=?");
8: ...
9: }catch (SQLException ex) {...}
10: // 자원을 사용하고 해제 시 항상 finally문에서 한다.
11: finally {
12: if ( conn!= null ) try { conn.close(); } catch (SQLException e){...}
13: if ( pstmt!= null ) try { pstmt.close(); } catch (SQLException e){...}
14: }

중간에 예외상황이 발생하더라도 함수가 종료되기 직전에 항상 finally문을 수행하므로, 자원을 해제할 경우 항상 finally문에서 해제한다.

라. 참고 문헌

[1] CWE-400 무제한 자원 소비 - http://cwe.mitre.org/data/definitions/400.html 
CWE-774 제한이나 조절 없이 파일 디스크립터나 핸들할당 - http://cwe.mitre.org/data/definitions/774.html 
CWE-789 무제어 메모리 할당 - http://cwe.mitre.org/data/definitions/789.html 
CWE-770 제한이나 조절 없이 자원할당 - http://cwe.mitre.org/data/definitions/770.html 
[2] M. Howard and D. LeBlanc. “Writing Secure Code”. Chapter 17, “Protecting Against Denial of Service Attacks” Page 517. 2nd Edition. Microsoft. 2002 
[3] J. Antunes, N. Ferreira Neves and P. Verissimo. “Detection and Prediction of Resource-Exhaustion Vulnerabilities”. Proceedings of the IEEE International

7절. 캡슐화

소프트웨어가 중요한 데이터나 기능성을 불충분하게 캡슐화 하는 경우, 인가된 데이터와 인가되지 않은 데이터를 구분하지 못하게 되어 허용되지 않는 사용자들 간의 데이터 누출이 가능해진다. 캡슐화는 단순히 일반 소프트웨어 개발 방법상의 상세한 구현 내용을 감추는 일뿐 아니라 소프트웨어 보안 측면의 좀 더 넓은 의미로 사용된다.

1. 세션 간에 데이터 누출(Data Leak Between Sessions)

가. 정의

다중 스레드 환경에서는 싱글톤(singleton) 객체 필드에 경쟁 조건(race condition)이 발생할 수 있다. 따라서 다중 스레드 환경에서 서블릿(servlet)에 정보를 저장하는 필드가 포함되지 않도록 하여 세션에서 데이터를 접근할 수 없도록 해야 한다.

나. 안전한 코딩기법

HttpServlet 클래스의 하위클래스에서 멤버 필드를 선언하면 안된다. 필요한 경우 지역 변수를 선언하여 사용한다.

다. 예제

안전하지 않는 코드 예제


1: public class U488 extends HttpServlet {
2: private String name;
3: protected void doPost(HttpServletRequest request, HttpServletResponse response)
4: throws ServletException, IOException {
5: name = request.getParameter("name");
6: ……
7: out.println(name + ", thanks for visiting!");
8: }
9: }

두 사용자가 거의 동시에 접속할 시, 첫번째 사용자를 위한 스레드가 out.println(…)을 수행하기 전에 두번째 사용자의 스레드가 name = … 을 수행하면 첫번째 사용자는 두번째 사용자의 정보(name)를 보게 된다.

안전한 코드 예제


1: public class S488 extends HttpServlet {
2: protected void doPost(HttpServletRequest request, HttpServletResponse response)
3: throws ServletException, IOException {
4: // 지역변수로 변경한다.
5: String name = request.getParameter("name");
6: if (name == null || "".equals(name)) return;
7: out.println(name + ", thanks for visiting!");
8: }
9: }

필요한 경우 지역변수를 선언하여 사용한다.

라. 참고 문헌

[1] CWE-488 세션 간에 데이터 누출 - http://cwe.mitre.org/data/definitions/488.html

2. 제거되지 않고 남은 디버거 코드(Leftover Debug Code)

가. 정의

디버깅 목적으로 삽입된 코드는 개발이 완료되면 제거해야 한다. 만일, 남겨진 채로 배포될 경우 공격자가 식별 과정을 우회하거나 의도하지 않은 정보와 제어 정보가 누출될 수 있다.

나. 안전한 코딩기법

J2EE와 같은 응용프로그램에서 main() 메소드를 정의하면 안된다. 이것은 보통 디버깅을 위해서 만드는 경우가 있는데, 디버깅이 끝나면 main() 메소드를 삭제해야 한다.

다. 예제

안전하지 않는 코드 예제


1: public class U489 extends HttpServlet {
2: protected void doGet(HttpServletRequest request, … ) throws …… { …… }
3: protected void doPost(HttpServletRequest request, … ) throws …… { …… }
4: // 테스트를 위한 main()함수나 디버깅용 로그 출력문 등이 남아 있다.
5: public static void main(String args[]) {
6: System.err.printf("Print debug code");
7: }
8: ……

J2EE와 같은 응용프로그램에서 디버깅용으로 사용되는 main() 메소드는 삭제되어야 한다.

안전한 코드 예제


1: public class S489 extends HttpServlet {
2: protected void doGet(HttpServletRequest request, … ) throws …… { …… }
3: protected void doPost(HttpServletRequest request, … ) throws …… { …… }
4: //테스트용 코드는 제거해준다.

J2EE와 같은 응용프로그램에서 디버깅용 main() 메소드는 삭제한다.

라. 참고 문헌

[1] CWE-489 제거되지 않고 남은 디버거 코드 - http://cwe.mitre.org/data/definitions/489.html

3. 민감한 데이터를 가진 내부 클래스 사용(Use of Inner Class Containing Sensitive Data)

가. 정의

내부 클래스는 컴파일 과정에서 패키지 수준의 접근성으로 바뀌기 때문에 의도하지 않은 정보 공개가 발생할 수 있다. 이를 피하기 위해서는 정적(static) 내부 클래스, 지역적(local) 내부 클래스 또는 익명(anonymous) 내부 클래스를 사용하는 것을 고려해야 한다.

나. 안전한 코딩기법

내부클래스 사용 시 외부클래스의 private 필드를 접근하지 않도록 한다. 가급적이면 내부 클래스를 사용하지 않도록하며, 불가피하게 내부클래스를 사용할 경우, 정적(static) 또는 지역적(local) 또는 익명(anonymous) 내부 클래스를 사용해야 한다.

다. 예제

안전하지 않는 코드 예제


1: public final class U492 extends Applet {
2: // 외부 클래스에서 내부 클래스로 가면서 보안 수준을 낮추어서는 않된다.
3: public class urlHelper { String openData = secret; }
4: String secret;
5: urlHelper helper = new urlHelper();
6: }

내부 클래스는 바이트코드에서는 패키지 수준 접근제어로 바뀌기 때문에, 내부 클래스가 둘러싸고 있는 클래스의 민감한 정보에 접근시, 이 내부 클래스를 통해 정보가 유출될 수 있다.

안전한 코드 예제


1: public class S492 extends Applet {
2: // 내부 클래스를 정적(static) 선언하여 외부클래스의 private 필드에 접근 못하게 한다.
3: public static class urlHelper { ... }
4: String secret;
5: urlHelper helper = new urlHelper(secret);
6: }
7:

내부클래스의 사용에 주의해서 내부클래스에서 외부클래스의 private 필드를 접근하지 않도록 한다.

라. 참고 문헌

[1] CWE-492 민감한 데이터를 가진 내부 클래스 사용 - http://cwe.mitre.org/data/definitions/492.html

4. Final 변경자 없는 주요 공용 변수(Critical Public Variable Without Final Modifier)

가. 정의

public으로 선언된 멤버 변수를 final로 선언하지 않으면, 그 변수의 값을 외부에서 변경할수 있다. 일반적으로 객체의 상태 변경은 허용된 인터페이스만 사용하도록 해야 한다.

나. 안전한 코딩기법

변경되면 안되는 public 멤버 변수는 반드시 final로 한다.

다. 예제

안전하지 않는 코드 예제


1: public final class U493 extends Applet {
2: // price 필드가 final이 아니기 때문에, 외부에서 price를 수정할 수 있다.
3: public static float price = 500;
4:
5: public float getTotal(int count) {
6: return price * count;
7: }
8: ……

price 필드가 final이 아니기 때문에, 외부에서 변경이 가능하며, getTotal()의 값이 변조될수 있다.

안전한 코드 예제


1: public final class S493 extends Applet {
2: // 수정되면 안되는 변수는 final 키워드로 선언한다.
3: public static final float price = 500;
4:
5: public float getTotal(int count) {
6: return price * count; // price 수정 불가
7: }
8: }

변경되면 안되는 public 멤버 변수는 final 키워드로 선언한다.

라. 참고 문헌

[1] CWE-493 Final 변경자 없는 주요 공용 변수 - http://cwe.mitre.org/data/definitions/493.html

5. 공용 메소드로부터 리턴된 private 배열-유형 필드(Private Array-Typed Field Returned From A Public Method)

가. 정의

private로 선언된 배열을 public으로 선언된 메소드를 통해 반환(return)하면, 그 배열의 레퍼런스가 외부에 공개되어 외부에서 배열의 수정할 수 있다.

나. 안전한 코딩기법

private로 선언된 배열을 public으로 선언된 메소드를 통해 반환하지 않도록 해야 한다. 
필요한 경우 배열의 복제본을 반환하거나, 수정을 제어하는 public 메소드를 별도로 선언하여 사용한다.

다. 예제

안전하지 않는 코드 예제


1: // private 인 배열을 public인 메소드가 return한다
2: private String[] colors;
3: public String[] getColors() { return colors; }

멤버 변수 colors는 private로 선언되었지만 public으로 선언된 getColors() 메소드를 통해 reference를 얻을 수 있다. 이를 통해 의도하지 않은 수정이 발생할 수 있다.

안전한 코드 예제


1: ……
2: private String[] colors;
3: // 메소드를 private으로 하거나, 복제본을 반환하거나, 수정을 제어하는 public 메소드를 별도로 만든다.
4: public String[] getColors() {
5: String[] ret = null;
6: if ( this.colors != null ) {
7: ret = new String[colors.length];
8: for (int i = 0; i < colors.length; i++) { ret[i] = this.colors[i]; }
9: }
10: return ret;
11: }
12: ……

private 배열의 복제본을 만들어서, 그것을 반환하도록 작성하면 private 선언된 배열에 대한 의도하지 않은 수정을 방지할 수 있다.

라. 참고 문헌

[1] CWE-495 공용 메소드로부터 리턴된 private 배열-유형 필드 - http://cwe.mitre.org/data/definitions/495.html

6. private 배열-유형 필드에 공용 데이터 할당 (Public Data Assigned to Private Array-Typed Field)

가. 정의

public으로 선언된 데이터 또는 메소드의 인자가 private 선언된 배열에 저장되면, private 배열을 외부에서 접근할 수 있다.

나. 안전한 코딩기법

public으로 선언된 데이터가 private 선언된 배열에 저장되지 않도록 한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: // userRoles 필드는 private이지만, public인 setUserRoles()를 통해 외부의 배열이 할당되면,사실상 public 필드가 된다.
3: private String[] userRoles;
4:
5: public void setUserRoles(String[] userRoles) {
6: this.userRoles = userRoles;
7: }
8: ……

userRoles 필드는 private이지만, public인 setUserRoles()를 통해 외부의 배열이 할당되면,사실상 public 필드가 된다.

안전한 코드 예제


1: ……
2: // 객체가 클래스의 private member를 수정하지 않도록 한다.
3: private String[] userRoles;
4:
5: public void setUserRoles(String[] userRoles) {
6: this.userRoles = new String[userRoles.length];
7: for (int i = 0; i < userRoles.length; ++i)
8: this.userRoles[i] = userRoles[i];
9: }
10: ……

입력된 배열의 reference가 아닌, 배열의 “값”을 private 배열의 할당함으로써 private 멤버로서의 접근권한을 유지 시켜준다.

라. 참고 문헌

[1] CWE-496 private 배열-유형 필드에 공용 데이터 할당 - http://cwe.mitre.org/data/definitions/496.html

7. 시스템 데이터 정보 누출(Information Leak of System Data)

가. 정의

시스템의 내부 데이터나 디버깅 관련 정보가 공개되면, 이를 통해 공격자에게 아이디어를 제공하는 등 공격의 빌미가 된다.

나. 안전한 코딩기법

디버깅을 위해 작성한 시스템 정보 출력 코드를 모두 삭제해야 한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public void f() {
3: try { g(); }
4: catch (IOException e) {
5: // 예외 발생시 printf(e.getMessage())를 통해 오류 메시지 정보가 유출된다.
6: System.err.printf(e.getMessage());
7: }
8: }
9: private void g() throws IOException { …… }
10: …

예외 발생시 getMessage()를 통해 오류와 관련된 시스템 에러정보 등 민감한 정보가 유출될 수 있다.

안전한 코드 예제


1: ……
2: public void f() {
3: try { g(); }
4: catch (IOException e) {
5: // end user가 볼 수 있는 오류 메시지 정보를 생성하지 않아야 한다.
6: System.err.println(" IOException Occured" );
7: }
8: }
9: private void g() throws IOException { …… }
10: ……

가급적이면 공격의 빌미가 될 수 있는 오류와 관련된 상세한 정보는 최종 사용자에게 노출하지 않는다.

라. 참고 문헌

[1] CWE-497 시스템 데이터 정보 누출 - http://cwe.mitre.org/data/definitions/497.html

8. 동적 클래스 로딩 사용(Use of Dynamic Class Loading)

가. 정의

동적으로 클래스를 로드하면 그 클래스가 악성 코드일 가능성이 있다. 동적으로 클래스를 로드하지 말아야 한다.

나. 안전한 코딩기법

동적 로딩은 사용하지 않는다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public void f() {
3: // 외부 입력으로 동적 클래스 로딩
4: String classname = System.getProperty("customClassName" );
5: try {
6: Class clazz = Class.forName(classname);
7: System.out.println(clazz);
8: } catch (ClassNotFoundException e) { …… }
9: ……

동적으로 로드되는 클래스는 악성 코드일 수 있다.

안전한 코드 예제


1: ……
2: public void f() {
3: //외부 입력으로 동적 클래스 로딩하지 않도록 한다.
4: TestClass tc = new TestClass();
5: System.out.println(tc);
6: …

가급적이면 동적 로딩을 사용하지 않는다. 사용해야 하는 경우 로드가 가능한 모든 클래스를 미리 정의하여 사용한다.

라. 참고 문헌

[1] CWE-545 동적 클래스 로딩 사용 - http://cwe.mitre.org/data/definitions/545.html

추적: • JAVA 보안 개발 가이드

 

about author

PHRASE

Level 60  머나먼나라

새는 높이 날아서 주살을 쏘는 활의 해에서 피한다. 사람도 뜻(志)을 고상하게 하여 몸을 지키는 방법을 생각해야 한다. -장자

댓글 ( 0)

댓글 남기기

작성
  •    
  •  

자바 목록    more