소프트웨어 개발보안 가이드 분석(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) : 해제된 자원 사용