소프트웨어 개발보안 가이드 분석(2021) : 암호화되지 않은 중요정보

사용자 또는 시스템의 중요정보가 포함된 데이터를 평문으로 송수신 ·또는 저장할 때

인가되지 않은 사용자에게 민감한 정보가 노출 될 수 있는 보안약점이다.

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

중요정보 평문 저장(왼쪽) / 중요정보 평문전송(오른쪽)

사용자의 개인정보, 금융정보, 기업의 기밀정보 등 중요정보가 유출되면 그에 따른 피해는 엄청날 수 있습니다. 이러한 중요정보를 보호하는 가장 기본적인 수단 중 하나는 암호화입니다. 그러나 그러한 정보들이 암호화되지 않았다면 많은 위협을 받을 수 있습니다.

이번 포스팅에서는 암호화되지 않은 중요정보에 대해 알아보고 취약한 코드 예제와 이를 방지하기 위한 안전한 코드 작성 방법을 살펴보려고 합니다.

암호화되지 않은 중요정보란?

암호화되지 않은 중요정보란 언어 뜻대로 해석을 해도 무방합니다. 중요정보는 사람들의 개인정보, 금융정보, 인증정보 등으로 민감한 정보를 말합니다. 이러한 중요정보는 저장 또는 정보통신망을 통한 송·수신 과정에서 암호화된 상태를 유지해야 합니다. 만약 암호화되지 않으면 공격자는 쉽게 정보에 접근하여 획득할 수 있기 때문입니다.

 

공격 메커니즘

암호화되지 않은 중요정보의 경우 공격자들에게 매우 유용한 공격 대상이 될 수 있습니다. 공격자들은 다음과 같은 공격 메커니즘을 통해 암호화되지 않은 중요정보를 탈취합니다.

  1. 노출된 데이터 탈취 : 데이터가 암호화되지 않으면, 공격자는 데이터베이스 또는 파일 시스템과 같은 저장소에서 접근만 성공한다면 중요정보를 손쉽게 얻을 수 있습니다.
  2. 네트워크 스니핑 : 암호화되지 않은 데이터가 네트워크를 통해 전송될 때, 공격자는 네트워크 스니핑 공격을 통해 중요정보를 가로챌 수 있습니다.
  3. 물리적 접근 : 물리적 보안 조치가 부족한 경우, 공격자는 물리적으로 시스템에 접근하여 중요정보들을 옮겨 적거나, 복사 등의 방법을 통해 획득할 수 있습니다.

 

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

  • 평문 전송
    1       String url = "http://example.com/login";
    1       String username = "user123";
    1       String password = "password123";
            
    2       String urlParameters = "username=" + URLEncoder.encode(username, "UTF-8") + 
                                    "&password=" + URLEncoder.encode(password, "UTF-8");
            
    3       // HTTP 연결 설정
            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            connection.setDoOutput(true);
            
     4      // 요청 보내기
            DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
            wr.writeBytes(urlParameters);
  • 1 : 해당 url에 HTTP 통신을 사용하여 평문 username과 password를 이용해 로그인 요청을 합니다.
  • 2 : username과 password를 전송하기 위해 인코딩하여 url 파라미터를 생성합니다.
  • 3, 4 : HTTP 통신 설정을 위해 HttpURLConnection을 사용하여 URL 연결 객체를 생성합니다.
  • 결과적으로 HTTP 통신을 하기 때문에 username과 password가 평문으로 전송됩니다.

  • 평문 저장
    public static void main(String[] args) throws IOException {
        String username = "user123";
        String password = "password123";

        BufferedWriter writer = new BufferedWriter(new FileWriter("credentials.txt"));
        writer.write("Username: " + username + "\n");
        writer.write("Password: " + password + "\n");
  • username과 password가 평문으로 파일(credentials.txt)에 저장되고 있습니다.
  • 다음과 같이 사용자 정보를 평문으로 저장하면, 파일이 유출될 경우 사용자의 개인정보가 공격자에게 노출되어 보안상 매우 취약합니다.

 

시큐어코딩 적용 방법

  • 암호화 전송
    public static void main(String[] args) {
            
    1       String url = "https://example.com/login";
    1       String username = "user123";
    1       String password = "password123";
            
            String urlParameters  = "username=" + URLEncoder.encode(username, "UTF-8") + "&";
                   urlParameters += "password=" + URLEncoder.encode(password, "UTF-8");
            
    2       // HTTPS 연결 설정
            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            connection.setDoOutput(true);
    }
  • 1 : 해당 url에 HTTPS 통신을 사용하여 암호화된 username과 password를 이용해 로그인 요청을 합니다.
  • 2 : HTTPS 연결을 설정하기 위해 HttpURLConnection을 사용하여 URL 연결 객체를 생성합니다.
  • 결과적으로 username과 password는 암호화되어 전송되기 때문에 공격자는 중요정보의 기밀을 유지할 수 있습니다.

  • 암호화 저장
    public static void main(String[] args) throws IOException, NoSuchAlgorithmException {
        String username = "user123";
        String password = "password123";

  1     // 비밀번호를 해시 함수를 사용하여 암호화
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] hashBytes = md.digest(password.getBytes());
        StringBuilder encryptedPassword = new StringBuilder();
 1.1    for (byte b : hashBytes) {
            encryptedPassword.append(String.format("%02x", b));
        }

        // 암호화된 비밀번호를 파일에 저장
  2     BufferedWriter writer = new BufferedWriter(new FileWriter("credentials.txt"));
        writer.write("Username: " + username + "\n");
        writer.write("Password: " + encryptedPassword.toString() + "\n");
    }
  • 1 : SHA-256 해시 알고리즘을 통해 password를 암호화합니다.
  • 1.1 : 2진 형식으로 저장되는 해시 알고리즘을 통한 암호화된 비밀번호를 텍스트 형식으로 파일에 저장하기 위하여 16진수로 변환합니다.
  • 2 : password가 해시 알고리즘으로 암호화되어 파일(credentials.txt)에 저장되고 있습니다.
  • 결과적으로 사용자의 중요정보인 비밀번호가 암호화되어 저장되면, 파일이 유출될 경우 공격자가 해독할 수 없기 때문에 password를 탈취할 수 없습니다.

  • 이전 소프트웨어 개발보안 가이드 분석(2021) : 취약한 암호화 알고리즘 사용
  • 다음 소프트웨어 개발보안 가이드 분석(2021) : 하드코드된 중요정보