소프트웨어 개발보안 가이드 분석(2021) : 무결성 검사 없는 코드 다운로드

원격으로부터 소스코드 또는 실행파일을 무결성 검사 없이 다운로드 받고, 이를 실행하는 제품들이 종종 존재한다.

이는 호스트 서버의 변조, DNS 스푸핑(Spoofing) 또는 전송 시의 코드 변조 등의 방법을 이용하여

공격자가 악의적인 코드를 실행할 수 있도록 한다.

소프트웨어 개발보안가이드(2021), 한국인터넷진흥원

 

무결성 검사 없는 코드 다운로드란?

"무결성 검사 없는 코드 다운로드"는 의미 그대로 무결성 검사를 하지 않고 소프트웨어를 다운로드하는 것입니다. 소프트웨어의 무결성은 그 내용이 변경되지 않았음을 보장하는 것으로, 이는 사용자가 다운로드한 코드가 개발자가 의도한 것과 동일한지를 확인하는 것을 의미합니다. 무결성 검사가 이루어지지 않으면 악의적인 개입으로 인해 소프트웨어가 변조될 가능성이 있는 보안약점입니다.

 

공격 메커니즘

무결성 검사가 없는 코드를 다운로드하는 것은 다음과 같이 여러 가지 공격 메커니즘에 취약한 상태를 초래할 수 있습니다.

  1. 악성 코드 삽입 : 다운로드한 코드에 악성 코드가 삽입될 수 있습니다. 이는 개인 정보 유출, 시스템 장악 등 다양한 보안 위협으로 이어질 수 있습니다.
  2. 피싱 : 소프트웨어가 변조되면 사용자가 의도하지 않은 정보를 입력하여 정보를 탈취하거나, 소프트웨어를 통해 보안정보가 노출될 수 있습니다.
  3. DNS 스푸핑 : 일반적으로 DNS 스푸핑은 DNS 질의(Query)에 대한 응답을 조작하여 사용자를 잘못된 IP 주소로 리다이렉션하는 공격입니다. "무결성 검사 없는 코드 다운로드" 취약점을 이용하면 사용자가 소프트웨어 다운로드 과정에서 코드를 변조할 수 있습니다. 이 변조된 코드는 DNS 스푸핑과 같은 공격을 수행하여 사용자를 잘못된 IP 주소로 리다이렉션합니다. 따라서 사용자가 악의적으로 조작된 DNS 응답을 받아 소프트웨어를 다운로드하게 되고, 그 소프트웨어는 악성 코드를 실행하거나, 악의적인 사이트로 사용자를 리다이렉션할 수 있습니다. 결과적으로 "무결성 검사 없는 코드 다운로드" 취약점을 통해 소프트웨어 다운로드 과정이 악의적으로 조작될 경우, DNS 스푸핑을 유발하여 사용자를 보안위협에 노출시킬 수 있습니다.

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

    public static void main(String[] args) {
  1     String maliciousURL = "http://example.com/malicious_code.jar";
  1     URL url = new URL(maliciousURL);

  2     url.openStream();
    }
  • 1 : 해당 URL에는 악성 코드가 위치해 있으며 이를 URL 객체로 생성하였습니다.
  • 2 : URL에서 바로 파일을 다운로드합니다.
  • 파일을 다운로드하는데, 이 과정에서 무결성 검사를 수행하지 않았습니다. 해당 URL에 있는 파일의 경우 공격자가 악성 코드를 삽입하여 변조된 파일이기 때문에 다운로드한 사용자 입장에서는 악성 코드가 실행될 것입니다. 이처럼 무결성 검사를 하지 않는 경우 개발자가 처음 의도한 것이 아닌 변조된 행위를 수행하게 되어 보안 위협을 가할 수 있습니다.

 

시큐어코딩 적용 방법

public class SafeCodeDownload {

    public static void main(String[] args) {
  1     String safeURL = "http://example.com/safe_code.jar";
  1     URL url = new URL(safeURL);
  1     HttpURLConnection connection = (HttpURLConnection) url.openConnection();
  1     String downloadFilePath = "safe_code.jar";
  1     downloadFile(connection, downloadFilePath);

  2     String downloadedHash = calculateHash(downloadFilePath);

  3     String expectedHash = readExpectedHashFromFile("expectedHash.txt");

  4     if (downloadedHash != null && downloadedHash.equals(expectedHash)) {
            // 무결성 검사 통과(해시값 일치)
        } else {
            // 무결성 검사 실패(해시값 비일치)
        }
    }
 
    // 기대되는 해시값을 파일에서 읽어오는 메소드
 5  private static String readExpectedHashFromFile(String filePath) {
        BufferedReader reader = new BufferedReader(new FileReader(filePath));
        String expectedHash = reader.readLine();
        return expectedHash;

    // URL에서 파일 다운로드
    private static void downloadFile(HttpURLConnection connection, String filePath) throws IOException { ... }

    // 파일의 해시값을 계산하는 메소드
    private static String calculateHash(String filePath) throws IOException { ... }
    }
}
  • 1 : URL로부터 safe_code.jar 파일을 다운로드합니다.
  • 2 : calculateHash 메서드를 통해 다운로드한 파일의 해시값을 계산합니다.(해시값 A)
  • 3 : expectedHash.txt 파일에는 개발자가 의도한 다운로드한 파일의 해시값 원본이 담겨있어 해시값을 읽어옵니다.(해시값 B)
  • 4 : 해시값 A와 해시값 B가 일치한다면 이는 무결성 검사에 통과했다는 것을 의미하고 다르다면 무결성 검사에 실패한 것입니다.
  • 5 : 비교에 사용되는 해시값들은 미리 외부 파일에 정의하여 이를 불러옵니다.
  • 무결성 검사를 위해 해시값들을 소스코드상에 하드코딩하는 것은 관리의 어려움뿐만 아니라 노출의 위험이 있기 때문에 외부에 저장해 두어 이를 불러오는 것이 안전합니다.

무결성 검사 없는 코드 다운로드를 방지하기 위한 보안 대책은 다음과 같은 방법들이 있습니다.

  1. 공식 출처에서 다운로드: 소프트웨어나 라이브러리를 다운로드할 때는 공식 출처에서 다운로드하는 것이 중요합니다. 공식 출처에서 다운로드하면 소프트웨어의 무결성이 보장될 가능성이 높습니다.
  2. 디지털 서명 확인: 개발자나 출처에서 제공한 디지털 서명을 확인하여 소프트웨어의 무결성을 검증합니다. 디지털 서명이 있는 경우, 해당 서명을 확인하여 코드가 변경되지 않았음을 확인할 수 있습니다.
  3. 보안 패치 및 업데이트: 자바 애플리케이션에 사용되는 라이브러리 및 프레임워크는 항상 최신 보안 패치 및 업데이트를 적용해야 합니다.

  • 이전 소프트웨어 개발보안 가이드 분석(2021) : 솔트 없이 일방향 해시함수 사용
  • 다음 소프트웨어 개발보안 가이드 분석(2021) : 반복된 인증시도 제한 기능 부재