소프트웨어 개발보안 가이드 분석(2021) : 하드코드된 중요정보
프로그램 코드 내부에 하드코드된 패스워드 또는 암호화키를 포함하여 내부 인증에 사용하거나
암호화를 수행하면 중요정보(관리자 정보, 암호화된 정보 등)가 유출될 수 있는 보안취약점이다.
소프트웨어 개발보안가이드(2021), 한국인터넷진흥원
하드코드된 중요정보란?
- 하드코드(하드코딩)란 소프트웨어 개발에서 특정한 값이나 설정을 소스 코드에 직접 포함시키는 것을 의미합니다. 하드코딩은 특정한 상황에서는 편리할 수 있지만, 보안상의 문제와 유지 보수의 어려움을 발생시킬 수 있습니다.
- 즉, 하드코드된 중요정보란 소프트웨어에서 사용되는 중요한 데이터나 인증 정보 등이 소스 코드나 실행 파일에 직접 하드코딩되어 있는 상태를 의미합니다. 이로 인해 해커가 쉽게 해당 정보에 접근하여 시스템을 침투하거나 중요한 데이터를 유출할 수 있습니다.
공격 메커니즘
- 소스 코드 누출 : 하드코드된 중요정보가 소스 코드에 직접 포함되어 있으면, 공격자가 소스 코드에 접근하여 중요정보를 얻을 수 있습니다. 이러한 정보는 API 키, 암호화된 비밀번호, 데이터베이스 연결 정보 등이 될 수 있습니다.
- 리버스 엔지니어링 : 실행 파일이나 애플리케이션에서 하드코딩된 중요정보를 추출하기 위해 리버스 엔지니어링 기술이 사용될 수 있습니다. 이를 통해 공격자는 중요한 정보를 분석하고 악용할 수 있습니다.
- 인증 우회 : 하드코딩된 인증 정보를 악용하여 시스템의 인증 기능을 우회하는 공격입니다. 공격자는 하드코딩된 사용자 이름과 비밀번호를 이용하여 시스템에 로그인하거나 인증을 우회하여 권한을 얻습니다.
- 악의적인 행위 : 인증을 우회하여 권한을 얻은 공격자는 시스템에 접근하여 악성 코드 삽입, 정보 탈취 등 악의적인 행위를 수행합니다.
취약한 웹 애플리케이션의 예
- 하드코드된 비밀번호
public class HardcodedDBPasswordExample {
// 하드코드된 데이터베이스 연결 정보
1 private static final String DB_URL = "jdbc:mysql://localhost:3306/mydatabase";
1 private static final String DB_USER = "myuser";
2 private static final String DB_PASSWORD = "myHardcodedPassword123";
public static void main(String[] args) {
Connection connection = null;
3 connection = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
}
}
- 1 : 데이터베이스 연결을 위한 정보
- 2 : 데이터베이스 연결에 필요한 패스워드가 하드코딩 됩니다.(myHardcodedPassword123)
- 3 : 데이터베이스 연결 정보(DB의 URL, USER, 하드코드된 PASSWORD)를 이용하여 데이터베이스 연결
- 해당 코드는 상수로 데이터베이스 연결 정보를 하드코딩했습니다. 다만, 이렇게 하드코딩된 비밀번호를 사용하는 것은 보안상 위험하므로 외부 설정 파일이나 환경 변수를 사용하여 비밀번호를 안전하게 관리하는 것이 좋습니다.
- 하드코드된 암호화 키
public class AESEncryptionExample {
1 private static final String ENCRYPTION_KEY = "myHardcodedEncryptionKey";
public static void main(String[] args) {
2 String dataToEncrypt = "SensitiveData";
3 Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
4 SecretKeySpec secretKeySpec = new SecretKeySpec(ENCRYPTION_KEY.getBytes(), "AES");
5 cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
6 String encryptedData = Base64.getEncoder().encodeToString(cipher.doFinal(dataToEncrypt.getBytes()));
}
}
- 1 : AES 암호화에 사용할 키를 하드코딩 합니다.
- 2 : 예시를 위해 해당 문자열을 암호화합니다.
- 3 : AES 알고리즘을 사용하여 암호화를 수행할 객체를 생성합니다.
- 4 : 암호화 키를 바이트 배열로 변환합니다.
- 5 : 암호화 모드로 설정하고 사용할 키를 적용합니다.
- 6 : 2번의 문자열을 암호화하고, 결과를 Based64로 인코딩합니다.
- 결과적으로 암호화에 사용되는 암호화 키가 하드코딩되어 보안상의 위험이 있습니다. 따라서 안전한 방법으로 암호화 키를 관리해야 합니다.
시큐어코딩 적용 방법
- 하드코드 되지 않은 비밀번호
public class SecureDBConnectionExample {
public static void main(String[] args) {
Connection connection = null;
1 Properties properties = new Properties();
2 InputStream input = new FileInputStream("db.properties");
3 properties.load(input);
4 connection = DriverManager.getConnection(
properties.getProperty("db.url"),
properties.getProperty("db.user"),
properties.getProperty("db.password")
);
}
}
- 1 : 외부 설정 파일에서 읽어올 데이터베이스 연결 정보를 저장할 객체를 생성합니다.
- 2 : 외부 설정 파일(db.properties)을 읽어옵니다.
- 3 : input으로 읽어온 외부 설정 파일 데이터를 로드합니다.
- 4 : 외부 설정 파일에서 읽어온 정보를 이용해 데이터베이스에 연결합니다.
- 다음과 같이 소스코드 하드코딩 대신에 환경 변수를 사용하거나 외부 설정 파일에서 비밀번호를 불러 들여오는 것이 보안상 안전합니다.
- ※ db.properties 파일에는 하드코드된 비밀번호 코드에서 1~2의 코드가 작성되어 있습니다.
- 하드코드 되지 않은 암호화 키
public class SecureAESEncryptionExample {
public static void main(String[] args) {
String dataToEncrypt = "SensitiveData";
1 String encryptionKey = readEncryptionKeyFromFile("encryption.properties");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
Key secretKeySpec = new SecretKeySpec(encryptionKey.getBytes(), "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
String encryptedData = Base64.getEncoder().encodeToString(cipher.doFinal(dataToEncrypt.getBytes()));
}
// 외부 설정 파일에서 암호화 키를 읽어오는 메서드
2 private static String readEncryptionKeyFromFile(String filename) throws IOException {
Properties properties = new Properties();
try (InputStream input = new FileInputStream(filename)) {
properties.load(input);
return properties.getProperty("encryption.key");
}
}
}
- 1 : readEncryptionKeyFromFile메서드를 통해 외부 설정 파일(encryption.key)에서 암호화 키를 읽어옵니다.
- 2 : encryption.key 파일에 설정되어 있는 암호화 키를 읽어와 리턴합니다.
- 결과적으로 소스코드에는 암호화 키를 작성하지 않고 외부의 파일로부터 불러 들여오기 때문에 코드의 안전성이 향상됩니다.