차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

양쪽 이전 판이전 판
다음 판
이전 판
다음 판양쪽 다음 판
guide:java_개발_보안_가이드 [2013/12/24 04:17] 121.140.124.172guide:java_개발_보안_가이드 [2013/12/26 07:36] 121.140.124.172
줄 3368: 줄 3368:
 === 다. 예제 === === 다. 예제 ===
 <code | 안전하지 않는 코드 예제> <code | 안전하지 않는 코드 예제>
 +1: class FileMgmtThread extends Thread {
 +2:
 +3: private String manageType = "";
 +4:
 +5: public FileMgmtThread (String type) {
 +6: manageType = type;
 +7: }
 +8:
 +9: public void run() {
 +10: try {
 +11: if ( manageType.equals("READ") ) {
 +12: File f = new File("Test_367.txt");
 +13: if (f.exists()) { // 만약 파일이 존재하면 파일내용을 읽음
 +14: BufferedReader br = new BufferedReader(new FileReader(f));
 +15: br.close();
 +16: }
 +17: } else if ( manageType.equals("DELETE") ) {
 +18: File f = new File("Test_367.txt");
 +19: if (f.exists()) { // 만약 파일이 존재하면 파일을 삭제함
 +20: f.delete();
 +21: } else {
 +22: ;
 +23: }
 +24: }
 +25: } catch (IOException e) {
 +26: }
 +27: }
 +28: }
 +29:
 +30: public class CWE367 {
 +31: public static void main(String[] args) {
 +32: // 파일의 읽기와 파일을 삭제하는 것을 동시에 수행한다.
 +33: FileMgmtThread fileAccessThread = new FileMgmtThread("READ");
 +34: FileMgmtThread fileDeleteThread = new FileMgmtThread("DELETE");
 +35: fileAccessThread.start();
 +36: fileDeleteThread.start();
 +37: }
 +38: }
 +</code>
 +위 예제는 파일의 존재를 확인하는 부분과 실제로 파일을 사용하는 부분을 실행하는 과정에서 시간차가 발생하는 경우, 파일에 대한 삭제가 발생하여 프로그램이 예상하지 못하는 태로 수행될 수 있다. 또한 위 예제는 시간차를 이용하여 파일을 변경하는 등의 공격에 취약할 수 있다.
 +<code | 안전한 코드 예제>
 +1: class FileMgmtThread extends Thread {
 +2:
 +3: private static final String SYNC = "SYNC" ;
 +4:
 +5: private String manageType = "";
 +6:
 +7: public FileMgmtThread (String type) {
 +8: manageType = type;
 +9: }
 +10:
 +11: public void run() {
 +12: // synchronized 를 사용함으로써 지정된 객체에 lock이 걸려서
 +13: // 블록을 수행하는 동안 다른 Thread가 접근할 수 없다.
 +14: synchronized(SYNC) {
 +15: try {
 +16: if ( manageType.equals("READ") ) {
 +17: File f = new File("Test_367.txt");
 +18: if (f.exists()) { // 만약 파일이 존재하면 파일내용을 읽음
 +19: BufferedReader br = new BufferedReader(new FileReader(f));
 +20: br.close();
 +21: }
 +22: } else if ( manageType.equals("DELETE") ) {
 +23: File f = new File("Test_367.txt");
 +24: if (f.exists()) { // 만약 파일이 존재하면 파일을 삭제함
 +25: f.delete();
 +26: } else {
 +27: ;
 +28: }
 +29: }
 +30: } catch (IOException e) {
 +31: }
 +32: }
 +33: }
 +34: }
 +35:
 +36: public class CWE367 {
 +37: public static void main(String[] args) {
 +38: // 파일의 읽기와 파일을 삭제하는 것을 동시에 수행한다.
 +39: FileMgmtThread fileAccessThread = new FileMgmtThread("READ");
 +40: FileMgmtThread fileDeleteThread = new FileMgmtThread("DELETE");
 +41: fileAccessThread.start();
 +42: fileDeleteThread.start();
 +43: }
 +44: }
 +</code>
 +공유자원(예를 들어, 파일)을 여러 스레드가 접근하여 사용할 경우, 동기화 구문을 이용하여 한 번에 하나의 스레드만 접근 가능하도록 변경한다.
 +<code | 안전하지 않는 코드 예제>
 +1: public class MyServlet extends HttpServlet {
 +2: String name;
 +3: public void doPost ( HttpRequestRequest hreq, HttpResponceServlet hres ) {
 +4: name = hreq.getParameter("name");
 +5: …….
 +6: }
 +</code>
 +HttpServet을 상속받은 MyServlet이 멤버필드로 name을 사용하고 있다. name은 MyServlet을 동시에 사용하는 모든 사용자에게 정보가 노출된다.
 +<code | 안전한 코드 예제>
 +1: public class MyServlet extends HttpServlet {
 +2: public void doPost ( HttpRequestRequest hreq, HttpResponceServlet hres ) {
 +3: // 서블릿 프로그램의 멤버 변수는 공용으로 사용하기 때문에 로컬로 정의해서 사용한다.
 +4: String name = hreq.getParameter("name");
 +5: ...
 +6: }
 +</code>
 +name을 doPost 메소드에만 사용할 수 있도록 로컬로 정의하여 경쟁상태를 제거한다.
 +<code | 안전한 코드 예제>
 +1: public class MyClass {
 +2: String name;
 +3: public void doProcess (HttpRequestRequest hreq ) {
 +4: // 멤버변수 공유 시 동기화시킨다.
 +5: synchronized {
 +6: name = hreq.getParameter("name");
 +7: ...
 +8: }
 +9: ...
 +10: }
 +</code>
 +업무상 name을 여러 쓰레드 사이에서 공유해야 한다면, synchronized 문장을 사용하여,임계코드가 쓰레드들 간 동기화할 필요가 있다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-367 경쟁 조건: 검사시점과 사용시점 - http://cwe.mitre.org/data/definitions/367.html
 +\\
 +[2] SANS Top 25 Most Dangerous Software Errors
 +\\
 +[3] Michael Howard, David LeBlanc and John Viega. "24 Deadly Sins of Software Security"."Sin 13: Race Conditions." Page 205. McGraw-Hill. 2010
 +\\
 +[4] Andrei Alexandrescu. "volatile - Multithreaded Programmer's Best Friend". Dr. Dobb's. 2008-02-01
 +\\
 +[5] Steven Devijver. "Thread-safe webapps using Spring" David Wheeler. "Prevent race conditions". 2007-10-04
 +\\
 +[6] Matt Bishop. "RaceConditions, Files, andSecurityFlaws; or the Tortoise andtheHareRedux". September 1995
 +\\
 +[7] Johannes Ullrich. "Top 25 Series - Rank 25 - Race Conditions". SANS Software Security Institute. 2010-03-26
 +==== 4. J2EE 잘못된 습관: 스레드의 직접 사용(J2EE Bad Practices: Direct Use of Threads) ====
 +
 +=== 가. 정의 ===
 +J2EE 표준은 웹 응용프로그램에서 스레드 사용을 금지하고 있다. 따라서 스레드를 직접 사용하는 것 대신에 해당 플랫폼에서 제공하는 병렬 실행을 위한 프레임워크를 사용해야 한다. 그렇지 않을 경우, 교착 상태, 경쟁 조건, 및 기타 동기화 오류 등이 발생한다.
 +=== 나. 안전한 코딩기법 ===
 +J2EE에서는 스레드를 사용하는 것 대신에 병렬 실행을 위한 프레임워크를 사용해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: public class U383 extends HttpServlet {
 +2: protected void doGet(HttpServletRequest request, HttpServletResponse response)
 +throws ServletException, IOException {
 +3: // Thread를 만들고 background에서 작업을 수행한다.
 +4: Runnable r = new Runnable() {
 +5: public void run() {
 +6: System.err.println("do something");
 +7: }
 +8: };
 +9: new Thread(r).start();
 +10: }
 +11: }
 +</code>
 +J2EE 프로그램에서 스레드를 직접 생성하여 사용하면, 교착 상태, 경쟁 조건, 및 기타 동기화 오류 등이 발생할 수 있다.
 +<code | 안전한 코드 예제>
 +1: public class S383 extends HttpServlet {
 +2: protected void doGet(HttpServletRequest request, HttpServletResponse response)
 +throws ServletException, IOException {
 +3: // 수행할 Thread에 대해서 일반 자바 클래스를 만든다.
 +4: // New MyClass().main();
 +5:
 +6: // 만약 async로 병렬작업을 하기 위해서는 JAVA Runtime을
 +7: // 사용하여 async로 통신하는 게 좋다.
 +8: Runtime.getRuntime().exec("java AsyncClass" );
 +9: }
 +10: }
 +11:
 +12: class AsyncClass {
 +13: public static void main(String args[]) {
 +14: // Process and store request statistics.
 +15: // ……
 +16: System.err.println("do something");
 +17: }
 +18: }
 +</code>
 +스레드를 직접 사용하는 것 대신에 해당 플랫폼에서 제공하는 병렬 실행을 위한 프레임워크를 사용한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-383 J2EE 잘못된 습관: 스레드의 직접 사용 - http://cwe.mitre.org/data/definitions/383.html
 +\\
 +[2] Java 2 Platform Enterprise Edition Specification, v1.4, Sun Microsystems
 +==== 5. 심볼릭명이 정확한 대상에 매핑되어 있지 않음(Symbolic Name not Mapping to Correct Object) ====
 +
 +=== 가. 정의 ===
 +심볼릭명을 사용하여 특정 대상을 지정하는 경우 공격자는 심볼릭명이 가리키는 대상을 작하여 프로그램이 원래 의도했던 동작을 못하게 할 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +클래스 객체가 필요할 때에는 클래스 생성자를 표준적인 방법으로만 호출해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public void f() throws ClassNotFoundException, InstantiationException,
 +IllegalAccessException {
 +3: // Class.forName으로 클래스를 생성하고 있다.
 +4: Class c = Class.forName("testbed.unsafe.U386.Add");
 +5: Object obj = (Add)c.newInstance();
 +6: Add add = (Add) obj;
 +7: System.out.println(add.add(3, 5)); // 34
 +8:
 +9: Object obj2 = (Add)Class.forName(" testbed.unsafe.Add" ).newInstance();
 +10: Add add2 = (Add) obj2;
 +11: System.out.println(add2.add(3, 5)); // 8
 +12: }
 +13:
 +14: class Add {
 +15: int add(int x, int y) {
 +16: return x + y;
 +17: }
 +18: }
 +19: }
 +20:
 +21: class Add {
 +22: int add(int x, int y) { return (x*x + y*y); }
 +23: }
 +</code>
 +java.lang.Class.forName()은 인수 문자열을 기반으로 해당 클래스를 반환(return)하지만, 문자열이 "이름"으로서 지시하는 클래스가 언제나 동일한 메소드를 구현하고 있음을 보장하지 못한다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: public void f() throws ClassNotFoundException,
 +3: InstantiationException, IllegalAccessException {
 +4: // 객체의 생성은 직접 생성자를 호출하여 생성한다.
 +5: testbed.safe.S386.Add add = new testbed.safe.S386.Add();
 +6: System.out.println(add.add(3, 5));
 +7: testbed.safe.Add add2 = new testbed.safe.Add();
 +8: System.out.println(add2.add(3, 5));
 +9: }
 +10:
 +11: class Add {
 +12: private int add(int x, int y) {
 +13: return x + y;
 +14: }
 +15: }
 +16: }
 +17:
 +18: class Add {
 +19: int add(int x, int y) { return (x*x + y*y); }
 +20: }
 +</code>
 +java.lang.Class.forName 대신, 각 클래스의 생성자를 제대로 호출하여 객체를 생성한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-386 심볼릭명이 정확한 대상에 매핑되어 있지 않음 - http://cwe.mitre.org/data/definitions/386.html
 +==== 6. 중복 검사된 잠금(Double-Checked Locking) ====
 +
 +=== 가. 정의 ===
 +중복 검사된 잠금(double-checked locking)은 프로그램의 효율성을 높이기 위해 사용하지만, 의도한 대로 동작하지 않는다.
 +\\
 +동기화 비용을 줄이기 위해, 프로그래머는 하나의 객체만 할당될 수 있도록 코드를 작성하지만, 자바에서는 객체 참조 주소를 할당하고 생성자를 호출하므로 의도한 객체가 완전하게 초기화되지 않은 상태에서 사용되는 경우가 발생할 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +특정 리소스가 (비)할당되었을 경우만 작업을 수행하도록 두 번에 걸쳐 검사를 시도해도 원하는 자원이 (비)할당되었는지 보장이 불가능하다.
 +\\
 +중복 검사된 잠금에 대한 완벽한 보장을 원할 경우 메소드를 동기화해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: Helper helper;
 +3:
 +4: public Helper MakeHelper() {
 +5: // helper 객체의 null 체크에 대해서는 동기화가 되지 않는다.
 +6: if (helper == null) {
 +7: synchronized (this) {
 +8: if (helper == null) {
 +9: helper = new Helper();
 +10: }
 +11: }
 +12: }
 +13: return helper;
 +14: }
 +15:
 +16: class Helper {
 +17: ……
 +18: }
 +19: }
 +</code>
 +위 예제는 하나의 helper 객체만 할당될 수 있도록 코드가 작성되었다. 이는 불필요한 동기화를 피하면서 스레드 안전성을 보장하는 것처럼 보인다. 그러나 자바에서는 객체 참조주소를 할당하고 생성자를 호출하므로, helper 객체가 완전하게 초기화되지 않은 상태에서 사용되는 경우가 발생할 수 있다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: Helper helper;
 +3:
 +4: // 메소드 전체에 대해 동기화를 하도록 설정함.
 +5: public synchronized Helper MakeHelper() {
 +6: if (helper == null) {
 +7: helper = new Helper();
 +8: }
 +9: return helper;
 +10: }
 +11: }
 +12:
 +13: class Helper {
 +14: ……
 +15: }
 +</code>
 +중복 검사된 잠금에 대한 완벽한 보장을 원할 경우, 메소드 전체에 대해 동기화를 하도록 설정한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-609 중복 검사된 잠금 - http://cwe.mitre.org/data/definitions/609.html
 +\\
 +[2] David Bacon et al.. "The "Double-Checked Locking is Broken" Declaration".
 +\\
 +http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
 +==== 7. 제대로 제어되지 않은 재귀(Uncontrolled Recursion) ====
 +
 +=== 가. 정의 ===
 +재귀의 순환횟수를 제어하지 못하여 할당된 메모리나 프로그램 스택 등의 자원을 과다하게 사용하면 위험하다. 대부분의 경우, 귀납 조건(base case)이 없는 재귀는 무한 재귀에 빠진다.
 +=== 나. 안전한 코딩기법 ===
 +무한 재귀를 방지하기 위하여 모든 재귀 호출을 조건문 블럭이나 반복문 블럭 안에서만 수행해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public int factorial(int n) {
 +3: // 재귀 호출이 조건문/반복문 블럭 외부에서 일어나면 대부분 무한 재귀를 유발한다.
 +4: return n * factorial(n - 1);
 +5: }
 +</code>
 +재귀적으로 정의되는 함수의 경우, 재귀 호출이 조건문/반복문 블럭 외부에서 일어나면 대부분 무한 재귀를 유발한다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: public int factorial(int n) {
 +3: int i;
 +4: // 모든 재귀 호출은 조건문이나 반복문 블럭 안에서 이루어져야한다.
 +5: if (n == 1) {
 +6: i = 1;
 +7: } else {
 +8: i = n * factorial(n - 1);
 +9: }
 +10: return i;
 +11: }
 +</code>
 +모든 재귀 호출은 조건문이나 반복문 블럭 안에서 이루어져야한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-674 제대로 제어되지 않은 재귀 - http://cwe.mitre.org/data/definitions/674.html
 +
 +===== 5절. 에러 처리 =====
 +정상적인 에러는 사전에 정의된 예외사항이 특정 조건에서 발생하는 에러이며, 비정상적인 에러는 사전에 정의되지 않은 상황에서 발생하는 에러이다. 개발자는 정상적인 에러 및 비정상적인 에러 발생에 대비한 안전한 에러처리 루틴을 사전에 정의하고 프로그래밍함으로써 에러처리 과정 중에 발생 할 수 있는 보안 위협을 미연에 방지 할 수 있다. 에러를 불충하게 처리(혹은 전혀 처리) 하지 않을 때 혹은 에러 정보에 과도하게 많은 정보를 포함하여 이를 공격자가 악용 할 수 있을 때 보약취약점이 발생할 수 있다.
 +==== 1. 취약한 패스워드 요구조건(Weak Password Requirements) ====
 +
 +=== 가. 정의 ===
 +사용자에게 강한 패스워드를 요구하지 않으면 사용자 계정을 보호하기 힘들다.
 +=== 나. 안전한 코딩기법 ===
 +패스워드 관련해서 강한 조건이 필요하다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public void doPost(HttpServletRequest request, HttpServletResponse response)
 +3: throws IOException, ServletException {
 +4: try {
 +5: String id = request.getParameter("id");
 +6: String passwd = request.getParameter("passwd" );
 +7: // 패스워드 복잡도 검증 없이 가입 승인 처리
 +8: ....
 +9: } catch (SQLException e) { …… }
 +10: }
 +</code>
 +위 예제와 같이 가입자가 입력한 패스워드에 대한 복잡도 검증 없이 가입 승인 처리를 수행하게 되면 사용자 계정을 보호하기 힘들게 된다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: private static final String CONNECT_STRING = "jdbc:ocl:orcl";
 +3:
 +4: public void doPost(HttpServletRequest request, HttpServletResponse response)
 +5: throws IOException, ServletException {
 +6: try {
 +7: String id = request.getParameter("id");
 +8: String passwd = request.getParameter("passwd");
 +9:
 +10: // passwd에 대한 복잡도 검증
 +11: if (passwd == null || " " .equals(passwd)) return;
 +12: if (!passwd.matches(" ") && passwd.indexOf("@!#") > 4 && passwd.length() > 8) {
 +13: // passwd 복잡도 검증 후, 가입 승인 처리
 +14: }
 +15: } catch (SQLException e) { …… }
 +16: catch (NamingException e) { …… }
 +17: }
 +</code>
 +사용자 계정을 보호하기 위해 가입 시 패스워드 복잡도 검증 후 가입 승인처리를 수행한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-521 취약한 패스워드 요구조건 - http://cwe.mitre.org/data/definitions/521.html
 +\\
 +[2] OWASP Top Ten 2004 Category A3 - Broken Authentication and Session Management
 +==== 2. 오류 메시지 통한 정보 노출(Information exposure through an error message) ====
 +
 +=== 가. 정의 ===
 +SW는 오류 메시지를 통해 환경, 사용자, 관련 데이터 등의 프로그램 내부 정보를 유출될수 있다. 예를 들어 예외 발생 시 예외 이름이나 스택 트레이스를 출력하면 프로그램 내부 구조를 쉽게 파악할 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +최종 사용자에게 배포되는 SW에서는 내부 구조나 공격자에 활용될 수 있는 민감한 정보를 오류 메시지로 출력하지 말아야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public static void main(String[] args) {
 +3: String urlString = args[0];
 +4: try{
 +5: URL url = new URL(urlString);
 +6: URLConnection cmx = url.openConnection();
 +7: cmx.connect();
 +8: }
 +9: catch (Exception e) { e.printStackTrace(); }
 +10: }
 +</code>
 +예외 이름이나 스택 트레이스를 출력하면 프로그램 내부 정보가 유출된다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: public static void main(String[] args) {
 +3: String urlString = args[0];
 +4: try{
 +5: URL url = new URL(urlString);
 +6: URLConnection cmx = url.openConnection();
 +7: cmx.connect();
 +8: }
 +9: catch (Exception e) { System.out.println("연결 예외 발생" ); }
 +10:
 +</code>
 +예외 이름이나 스택 트레이스를 출력하지 않는다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-209 오류 메시지 통한 정보 노출 - http://cwe.mitre.org/data/definitions/209.html
 +==== 3. 오류 상황에 대한 처리 부재(Detection of Error Condition Without Action) ====
 +
 +=== 가. 정의 ===
 +오류는 포착했으나 그 오류에 대해서 아무 조치도 하지 않으면, 그 상태에서 계속 프로그램이 실행되므로 개발자가 의도하지 않은 결과를 초래한다.
 +=== 나. 안전한 코딩기법 ===
 +예외 또는 오류를 포착(catch)한 경우 그것에 대한 적절한 처리를 해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: private Connection conn;
 +3:
 +4: public Connection DBConnect(String url, String id, String password) {
 +5: try {
 +6: String CONNECT_STRING = url + ":" + id + ":" + password;
 +7: InitialContext ctx = new InitialContext();
 +8: DataSource datasource = (DataSource) ctx.lookup(CONNECT_STRING);
 +9: conn = datasource.getConnection();
 +10: } catch (SQLException e) {
 +11: //catch 블록이 비어있음
 +12: } catch (NamingException e) {
 +13: //catch 블록이 비어있음
 +14: }
 +15: return conn;
 +16: }
 +</code>
 +위 예제는 try 블록에서 발생하는 오류를 포착(catch)하고 있지만 그 오류에 대해서 아무조치를 하고 있지 않다. 따라서 프로그램이 계속 실행되기 때문에 프로그램에서 어떤 일이 일어났는지 전혀 알 수 없게 된다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: private Connection conn;
 +3:
 +4: public Connection DBConnect(String url, String id, String password) {
 +5: try {
 +6: String CONNECT_STRING = url + ":" + id + ":" + password;
 +7: InitialContext ctx = new InitialContext();
 +8: DataSource datasource = (DataSource) ctx.lookup(CONNECT_STRING);
 +9: conn = datasource.getConnection();
 +10: } catch (SQLException e) {
 +11: //Exception catch이후 Exception에 대한 적절한 처리를 해야 한다.
 +12: if ( conn != null ) {
 +13: try {
 +14: conn.close();
 +15: } catch (SQLException e1) {
 +16: conn = null;
 +17: }
 +18: }
 +19: } catch (NamingException e) {
 +20: //Exception catch이후 Exception에 대한 적절한 처리를 해야 한다.
 +21: if ( conn != null ) {
 +22: try {
 +23: conn.close();
 +24: } catch (SQLException e1) {
 +25: conn = null;
 +26: }
 +27: }
 +28: }
 +29: return conn;
 +30: }
 +</code>
 +예외를 포착(catch)한 후, 각각의 예외 사항(Exception)에 대하여 적절하게 처리해야 한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-390 오류 상황에 대한 처리 부재 - http://cwe.mitre.org/data/definitions/390.html
 +\\
 +[2] OWASP Top Ten 2004 Category A7 - Improper Error Handling
 +==== 4. 비정상적 혹은 예외적 조건의 부적절한 검사(Improper Check for Unusual or Exceptional Conditions) ====
 +
 +=== 가. 정의 ===
 +프로그램 수행 중에 함수의 결과 값에 대한 적절한 처리 또는 예외상황에 대한 조건을 적절하게 검사하지 않을 경우, 예기치 않은 문제를 야기할 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +값을 반환하는 모든 함수의 결과 값을 검사하여, 그 값이 기대한 값인지 검사하고, 예외처리를 사용하는 경우에 광범위한 예외처리 대신 구체적인 예외처리를 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: public void readFromFile(String fileName) {
 +2: try {
 +3: ...
 +4: File myFile = new File(fileName);
 +5: FileReader fr = new FileReader(myFile);
 +6: ...
 +7: } catch (Exception ex) {...}
 +8: }
 +</code>
 +함수의 인자로 fileName에 대한 Null 체크없이 File 객체를 생성하였으며, 광범위한 예외 클래스인 Exception을 사용하여 예외처리를 했다.
 +<code | 안전한 코드 예제>
 +1: public void readFromFile(String fileName) throws FileNotFoundException,
 +2: IOException,MyException {
 +3: try {
 +4: ...
 +5: // filename에 대한 널을 조사
 +6: if ( fileName == NULL ) throw new MyException("에러“);
 +7: File myFile = new File(fileName);
 +8: FileReader fr = new FileReader(myFile);
 +9: ...
 +10: // 함수 루틴에서 모든 가능한 예외에 대해서 처리한다.
 +11: } catch (FileNotFoundException fe) {...}
 +12: } catch (IOException ie) {...}
 +13: }
 +</code>
 +fileName이 Null 값인지 검사하고 Null이면 에러 메시지를 출력과 예외를 발생시킨다.
 +\\
 +또한 발생 가능한 모든 예외에 대한 구체적인 예외처리를 한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-754 부적절한 혹은 예외적 조건의 부적절한 검사 - http://cwe.mitre.org/data/definitions/754.html
 +\\
 +CWE-252 미점검 리턴 값 - http://cwe.mitre.org/data/definitions/252.html
 +\\
 +CWE-253 부정확한 함수 리턴 값 점검 - http://cwe.mitre.org/data/definitions/253.html
 +\\
 +CWE-273 부적절한 하락된 특권점검 - http://cwe.mitre.org/data/definitions/273.html
 +\\
 +CWE-296 부적절한 증명서 검증 신뢰체인 후속 - http://cwe.mitre.org/data/definitions/296.html
 +\\
 +CWE-297 부적절한 호스트-특정 증명서 데이터검증 - http://cwe.mitre.org/data/definitions/297.html
 +\\
 +CWE-298 부적절한 증명서 만료검증 - http://cwe.mitre.org/data/definitions/298.html
 +\\
 +CWE-299 부적절한 증명서 파기점검 - http://cwe.mitre.org/data/definitions/299.html
 +\\
 +[2] SANS Top 25 Most Dangerous Software Errors, http://www.sans.org/top25-software-errors/
 +\\
 +[3] M. Howard, D. LeBlanc, Writing Secure Code, Second Edition, Microsoft Press
 +===== 6절. 코드 품질 =====
 +작성 완료된 프로그램은 기능성, 신뢰성, 사용성, 유지보수성, 효율성, 이식성 등을 충족하기 위하여 일정 수준에 코드품질을 유지하여야 한다. 프로그램 코드가 너무 복잡하면 관리성,유지보수성, 가독성이 떨어질 뿐 아니라 다른 시스템에 이식하기도 힘들며, 프로그램에는 안전성을 위협할 취약점들이 코드 안에 숨겨져 있을 가능성이 있다.
 +==== 1. 코드 정확성: notify() 호출(Code Correctness: Call to notify()) ====
 +
 +=== 가. 정의 ===
 +스레드의 notify()를 직접 호출하면 살아 있는 스레드 중에서 어떤 스레드를 깨울지 불명확하다. 따라서 직접 호출하지 않는 것이 좋다.
 +=== 나. 안전한 코딩기법 ===
 +notify()를 직접 호출하면 어떤 스레드를 깨울지 불명확하므로 사용하지 않는 것이 좋다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public synchronized void notifyJob() {
 +3: boolean flag = true;
 +4: notify();
 +5: }
 +</code>
 +notify()를 직접 호출하면 어떤 스레드를 깨울지 불명확하다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: public synchronized void notifyJob() {
 +3: boolean flag = true;
 +4: //notify() 메소드를 사용하지 않는다.
 +5: }
 +</code>
 +notify() 메소드를 사용하지 않는다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-362 경쟁 상태 - http://cwe.mitre.org/data/definitions/362.html
 +\\
 +CWE-662 부적절한 동기화 - http://cwe.mitre.org/data/definitions/662.html
 +\\
 +[2] Sun Microsystems, Inc. Java Sun Tutorial - Concurrency
 +==== 2. 자원의 부적절한 반환(Improper Resource Shutdown or Release) ====
 +
 +=== 가. 정의 ===
 +프로그램의 자원, 예를 들면 열린 파일 기술자(open file descriptor), 힙 메모리(heap memory),소켓(socket) 등은 유한한 자원이다. 이러한 자원을 할당받아 사용한 후, 더 이상 사용하지 않는 경우에는 적절히 반환하여야 한다.
 +=== 나. 안전한 코딩기법 ===
 +자원을 획득하여 사용한 다음에는 finally 블록에서 반드시 자원을 해제하여야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public void processFile() throws SQLException {
 +3: Connection conn = null;
 +4: final String url = "jdbc:mysql://127.0.0.1/example?user=root&password=1234";
 +5: try {
 +6: Class.forName("com.mysql.jdbc.Driver");
 +7: conn = DriverManager.getConnection(url);
 +8: ……
 +9: // 예외발생시 할당 받은 자원이 반환되지 않는다.
 +10: conn.close();
 +11: } catch (ClassNotFoundException e) {
 +12: System.err.println("ClassNotFoundException occured");
 +13: } catch (SQLException e) {
 +14: System.err.println("SQLException occured");
 +15: } finally {
 +16:
 +17: ……
 +</code>
 +위의 예제는 데이터베이스에 연결된 후에 사용 중 예외가 발생하면 할당된 데이터베이스 컨넥션 및 JDBC 자원이 반환되지 않는다. 이와 같은 상황이 반복될 경우 시스템에서 사용 가능한 자원이 소진될 수 있다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: public void processFile() throws SQLException {
 +3: Connection conn = null;
 +4: String url = "jdbc:mysql://127.0.0.1/example?user=root&password=1234";
 +5: try {
 +6: Class.forName("com.mysql.jdbc.Driver");
 +7: conn = DriverManager.getConnection(url);
 +8: ……
 +9: } catch (ClassNotFoundException e) {
 +10: System.err.print("error");
 +11: } catch (SQLException e) {
 +12: System.err.print("error");
 +13: } finally {
 +14: ……
 +15: // 더 이상 사용하지 않으면 즉시 close()를 해줘야 한다.
 +16: conn.close();
 +17: ……
 +</code>
 +예외상황이 발생하여 함수가 종료될 때 예외의 발생 여부와 상관없이 finally 블록에서 할당받은 자원을 반환한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-404 자원의 부적절한 반환 - http://cwe.mitre.org/data/definitions/404.html
 +\\
 +[2] SANS Top 25 2009 - (SANS 2009) Risky Resource Management - CWE ID 404 Improper Resource Shutdown or Release
 +==== 3. 널포인터 역참조(NULL Pointer Dereference) ====
 +
 +=== 가. 정의 ===
 +널 포인터 역참조는 '일반적으로 그 객체가 NULL이 될 수 없다'라고 하는 가정을 위반했을 때 발생한다. 공격자가 의도적으로 NULL 포인터 역참조를 실행하는 경우, 그 결과 발생하는 예외 사항을 이용하여 추후의 공격을 계획하는 데 사용될 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +널이 될 수 있는 레퍼런스(reference)는 참조하기 전에 널 값인지를 검사하여 안전한 경우에만 사용해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public void f() {
 +3: String cmd = System.getProperty("cmd");
 +4: // cmd가 null인지 체크하지 않았다.
 +5: cmd = cmd.trim();
 +6: System.out.println(cmd);
 +7: ……
 +</code>
 +위 예제는 "cmd" 프로퍼티가 항상 정의되어 있다고 가정하고 있지만, 만약 공격자가 프로그램의 환경을 제어해 "cmd" 프로퍼티가 정의되지 않게 하면, cmd는 널이 되어 trim() 메소드를 호출 할 때 널 포인터 예외가 발생하게 된다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: public void f() {
 +3: String cmd = System.getProperty("cmd");
 +4: // cmd가 null인지 체크하여야 한다.
 +5: if (cmd != null) {
 +6: cmd = cmd.trim();
 +7: System.out.println(cmd);
 +8: } else System.out.println("null command");
 +9: ……
 +</code>
 +먼저 cmd가 널인지 검사한 후에 사용한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-476 널포인터 역참조 - http://cwe.mitre.org/data/definitions/476.html
 +==== 4. 코드 정확성: 부정확한 serialPersistentFields 조정자(Code Correctness: Incorrect serialPersistentFields Modifier) ====
 +
 +=== 가. 정의 ===
 +serialPersistentFields를 정확하게 사용하기 위해서는 ‘private static final’로 선언해야 한다. public으로 선언하여 공유하면 정확성을 해칠 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +serialPersistentFields를 정확하게 사용하려면 private, static, final로 선언해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: class List implements Serializable {
 +2: public ObjectStreamField[] serialPersistentFields =
 +{ new ObjectStreamField("myField", List.class) };
 +3: ……
 +4: }
 +</code>
 +serialPersistentFields를 정확하게 사용하기 위해서는 private, static, final로 선언해야 한다.
 +<code | 안전한 코드 예제>
 +1: class List implements Serializable {
 +2: private static final ObjectStreamField[] serialPersistentFields =
 +{ new ObjectStreamField("myField", List.class) };
 +3: ……
 +4: }
 +</code>
 +serialPersistentFields를 정확하게 사용하기 위해서는 private, static, final로 선언해야 한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-485 불충분한 캡슐화 - http://cwe.mitre.org/data/definitions/485.html
 +\\
 +[2] Sun Microsystems, Inc. Java Sun Tutorial
 +==== 5. 코드 정확성: Thread.run() 호출(Code Correctness: Call to Thread.run()) ====
 +
 +=== 가. 정의 ===
 +프로그램에서 스레드의 start() 대신에 run()을 호출하면 스레드가 생성되지 않고, 해당 un() 함수를 직접 호출하여 해당 run() 함수의 종료를 대기하게 된다. 즉, 프로그래머는 새로운 스레드를 시작시키려고 했지만, start() 대신에 run()을 호출함으로써 호출자의 스레드에서 run() 메소드를 실행하게 된다.
 +=== 나. 안전한 코딩기법 ===
 +스레드의 run() 대신에 start()를 수행하도록 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +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: }
 +</code>
 +start() 대신에 run() 메소드를 사용하고 있다.
 +<code | 안전한 코드 예제>
 +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: }
 +</code>
 +스레드의 start() 메소드를 사용한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-572 코드 정확성: Thread.run() 호출 - http://cwe.mitre.org/data/definitions/572.html