[Java] 부적절한 자원해제 Try-with-resources 로 자원 해제하기

2tsumo·2022년 5월 30일
0

java

목록 보기
1/6
post-custom-banner

이번에 회사에서 우리팀이 만든 cms를 sw보안 약점진단을 받았을때 터진 이슈 중 하나이다.

부적절한 자원해제
사용된 자원을 적절히 해제하지 않아 자원 누수가 발생하여 새로운 입력을 처리 할 수 없게 되는 보안 취약점.

프로그램의 자원, 예를 들면 열린 파일디스크립터(Open File Descriptor), 힙 메모리(Heap Memory), 소켓(Socket)등은 유한한 자원이다. 이러한 자원을 할당받아 사용하게 되면, 사용 후 반드시 반환 해 주어야 한다. 프로그램 오류 또는 에러로 사용이 끝난 자원을 반환하지 못하게 되면 프로그램이 새로운 입력을 처리 할 수가 없는 문제가 생길 수 있다.

예를들어 다음과 같은 코드는 자원이 반환되지 않아 문제를 일으킬 수 있다


InputStream in = null;
OutputStream out = null;
try {
    in = new FileInputStream(inputFile);
    out = new FileOutputStream(outputFile);
...
    FileCopyUtils.copy(fis, os);
    // 자원반환 실행 전에 오류가 발생할 ⑨우 자원이 반환되지 않으며, 할당된 모든 자원을 반환해야
    한다.
    in.close();
    out.close();
} catch (IOException e){
    logger.error(e);
}

따라서 우리는 코드를 수정해야 하는데 두가지 방법이 있다

(1) 기존의 자원 해제 방법 try-catch-finally로 자원 해제
Java7 이전에, try-catch-finally을 사용하여 파일을 열고 문자열을 모두 출력하는 코드


public static void main(String args[]) throws IOException {
    FileInputStream is = null;
    BufferedInputStream bis = null;
    try {
        is = new FileInputStream("file.txt");
        bis = new BufferedInputStream(is);
        int data = -1;
        while((data = bis.read()) != -1){
            System.out.print((char) data);
        }
    } finally {
        // close resources
        if (is != null) is.close();
        if (bis != null) bis.close();
    }
}

코드를 보면 try에서 InputStream 객체를 생성하고 finally에서 close를 한다. try 안의 코드를 실행하다 Exception이 발생하는 경우 모든 코드가 실행되지 않을 수 있기 때문에 finally에 close 코드를 넣어주어야 한다. 심지어 InputStream 객체가 null인지 체크해줘야 하며 close에 대한 Exception 처리도 해야 한다.

(2) Try-with-resources 로 자원 해제
Java7 이후로 Try-with-resources 로 자원 해제가 가능하다


public static void main(String args[]) {
    try (FileInputStream is = new FileInputStream("file.txt");
        BufferedInputStream bis = new BufferedInputStream(is)) {
        int data = -1;
        while ((data = bis.read()) != -1) {
            System.out.print((char) data);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

코드를 보면, try(...) 안에 InputStream 객체 선언 및 할당하였다. 여기에서 선언한 변수들은 try 안에서 사용할 수 있다. 코드의 실행 위치가 try 문을 벗어나면 try-with-resources는 try(...) 안에서 선언된 객체의 close() 메소드들을 호출한다. 그래서 finally에서 close()를 명시적으로 호출해줄 필요가 없다. 따라서 훨씬 더 코드가 간결해지고 깔끔해 지기 때문에 java7 이상은 이렇게 쓰도록 하자!!

  • try-with-resources에서 자동으로 close가 호출되는 것은 AutoCloseable을 구현한 객체에만 해당이된다
profile
👨‍💻
post-custom-banner

0개의 댓글