소프트웨어 개발보안 가이드 분석(2021) : 부적절한 자원 해제

부적절한 자원 해제란?

부적절한 자원 해제 취약점이란 애플리케이션에서 사용한 자원(메모리, 파일 핸들, 네트워크 연결 등)을 적절히 해제하지 않아 발생하는 보안 취약점입니다. 이 취약점은 시스템 리소스의 낭비를 초래하며, 결과적으로 시스템의 성능 저하, 서비스 거부(DoS) 공격을 유발할 수있습니다. 더 심각한 경우 메모리 누수가 발생하여 시스템의 안정성이 저하될 수 있습니다.

 

공격 메커니즘

부적절한 자원 해제 취약점을 이용할 수 있는 공격 메커니즘은 다음과 같습니다.

  1. 서비스 거부(DoS) 공격: 공격자는 이 취약점을 이용해 애플리케이션의 자원을 고갈시키는 공격을 수행할 수 있습니다. 결과적으로, 정상 사용자가 서비스를 이용할 수 없게 됩니다.
  2. 메모리 누수: 적절한 자원 해제가 이루어지지 않을 경우, 메모리 누수가 발생할 수 있습니다. 이는 시스템의 성능 저하와 안정성 문제로 이어질 수 있습니다.

 

취약한 웹 애플리케이션의 예

다음은 적절히 자원 해제하지 않는 예시 코드입니다.

import java.io.*;

public class ResourceLeakExample {
    public static void main(String[] args) {
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream("example.txt");
            // 파일에서 데이터를 읽어옴
            // 데이터 처리 작업 수행
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            // 파일을 닫지 않음
        }
    }
}

위의 코드에서는 파일을 열고 데이터를 읽어오는 작업을 수행하고 있지만, finally 블록에서 파일을 닫지 않고 있습니다. 이는 파일 리소스가 해제되지 않고 계속해서 시스템에 남아있게 됩니다.

 

시큐어코딩 적용 방법

​

자원을 제대로 해제하지 않으면 자원 누수가 발생하여 시스템의 성능 저하나 안정성 문제를 일으킬 수 있습니다. 또한, 이러한 취약점을 통해 공격자가 시스템을 공격할 수 있습니다. 이와 같은 보안 취약점에 대응하기 위한 방법은 다음과 같습니다.

  1. 명시적인 자원 해제: 프로그래밍에서 자원을 사용한 후에는 반드시 명시적으로 해제해야 합니다. 파일, 네트워크 연결, 데이터베이스 연결 등 다양한 자원에 적용됩니다. 자원을 해제하는 과정은 프로그램의 안정성을 유지하고, 자원 누수를 방지하는 데 중요한 역할을 하는데 자원 해제 방법은 다음과 같습니다.
    • finally 구문에서 해제: 자바에서 try-catch 구문을 사용하여 예외를 처리하고, finally 구문에서 자원을 해제하는 방법을 사용하여 자원을 반드시 해제되도록 보장합니다.
    • try-with-resources 구문 사용: 자바 7 이상에서는 try-with-resources 구문을 사용하여 자동으로 자원을 해제할 수 있습니다. 이 구문은 AutoCloseable 인터페이스를 구현한 자원에 대해 자동으로 close() 메서드를 호출하여 자원을 해제합니다.
  2. 예외 처리와 안전한 종료: 프로그램이 예외 상황이나 오류를 처리할 때도 자원이 올바르게 해제되도록 해야 합니다. 예외 발생 시에도 자원이 안전하게 해제되어야 합니다.
  3. 자원 해제 로직 검증: 코드 리뷰와 정적 분석 도구를 사용해 자원이 적절히 해제되는지 확인하여 자원 누수와 관련된 보안 취약점을 방지하도록 합니다.

​

다음은 Finally 블록 안에서 자원 해제하는 예시 코드입니다.

import java.io.*;

public class SecureResourceReleaseExample {
    public static void main(String[] args) {
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream("example.txt");
            // 파일에서 데이터를 읽어옴
            // 데이터 처리 작업 수행
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

위의 코드에서는 finally 블록에서 파일을 닫는 과정을 안전하게 수행하고 있습니다. 먼저, 파일 스트림이 null이 아닌지 확인한 후에 파일을 닫는 작업을 수행하고 있습니다. 이렇게 하면 예외가 발생하더라도 자원이 올바르게 해제될 수 있습니다.

  • 이전 소프트웨어 개발보안 가이드 분석(2021) : Null Pointer 역참조
  • 다음 소프트웨어 개발보안 가이드 분석(2021) : 해제된 자원 사용