: 애플리케이션의 보안 이벤트를 적절히 기록하고 이를 실기간으로 모니터링하지 않아 발생하는 위험
개발자는 애플리케이션의 위험에 따라 다음 제어 중 일부 또는 전부를 구현해야한다.
다음은 사용자를 인증하려고 시도하는 코드이다. 로그인 실패시 재시도를 하도록 한다. 하지만 실패한 로그인은 기록되지 않으며 공격자가 프로그램을 무차별 대입하려고 시도한 기록이 되지 않는 문제점이 있다.
** Bad code **
if LoginUser(){
// Login successful
RunProgram();
} else {
// Login unsuccessful
LoginRetry();
}
** Good code **
if LoginUser(){
// Login successful
log.warn("Login by user successful.");
RunProgram();
} else {
// Login unsuccessful
log.warn("Login attempt by user failed, trying again."); //실패한 로그 기록
LoginRetry();
}
로그 출력 시 출력 중립화를 올바르게 수행하지 않아서 발생하는 보안 취약점
출력 중립화란?

다음 웹 애플리케이션 코드는 요청 객체에서 정수 값을 읽으려고 시도한다. ParseInt 호출이 실패하면 입력은 무슨 일이 일어났는지 나타내는 오류 메시지와 함께 기록된다.
** Bad code **
String val = request.getParameter("val");
try {
int value = Integer.parseInt(val);
}
catch (NumberFormatException) {
log.info("Failed to parse val = " + val);
}
...
이 코드의 문제점
** Good code **
String val = request.getParameter("val");
val = sanitizeInput(val); // 입력값 중립화
try {
int value = Integer.parseInt(val);
} catch (NumberFormatException e) {
log.info("Failed to parse val = " + val); // 안전하게 로그 기록
}
보안 관련 정보(실패한 인증 시도, 권한 부족 오류)가 로그에 기록되지 않거나 불완전하게 기록되었을 때 발생하는 취약점
다음은 의심스러운 여러 로그인 시도를 기록하는 코드이다
** Bad Code **
function login($userName,$password){
if(authenticate($userName,$password)){ // 사용자인증수행
return True;
}
else{
incrementLoginAttempts($userName); // 로그인실패횟수증가
if(recentLoginAttempts($userName) > 5){ // 최근로그인시도횟수반환
writeLog("Failed login attempt by User: " . $userName . " at " + date('r') );
}
}
}
이 코드의 문제점
** Good Code **
function login($userName, $password) {
if (authenticate($userName, $password)) {
return True; // 인증 성공
} else {
incrementLoginAttempts($userName); // 실패 횟수 증가
writeLog("Failed login attempt by User: " . $userName . " at " . date('r'));
if (recentLoginAttempts($userName) > 5) { // 5회를 초과하면 추가 경고 로그
writeLog("WARNING: Multiple failed login attempts detected for User: " . $userName);
}
}
}
모든 실패한 로그인 시도를 기록/로그의 민감한 정보 보호/실패 임계값 초과 시 경고로그 추가
민감한 정보를 로그에 기록하여 정보 노출 위험을 초래하는 문제를 다룸.
애플리케이션이 동작 중 발생하는 이벤트를 기록하기 위해 로그를 사용하는 경우, 의도치 않게 민감한 정보(예: 비밀번호, 세션토큰, 개인 식별정보)를 포함시키면 보안 위협으로 이어질 수 있음
다음은 사용자가 입력한 비밀번호를 로그에 기록하는 코드 예시이다.
** Bad code **
// 사용자가 입력한 비밀번호를 로그에 기록
public boolean authenticate(String username, String password) {
if (isValidUser(username, password)) {
log.info("User authenticated: " + username + ", Password: " + password); // 비밀번호 노출
return true;
} else {
log.info("Failed login attempt for user: " + username + ", Password: " + password); // 비밀번호 노출
return false;
}
}
이 코드의 문제점
사용자의 비밀번호를 로그에 직접 기록하고, 만약 로그 파일이 외부에 노출되거나 공격자가 접근할 경우 비밀번호가 유출될 수 있는 문제가 있다.
** Good code **
public boolean authenticate(String username, String password) {
if (isValidUser(username, password)) {
log.info("User authenticated: " + username); // 비밀번호를 로그에 기록하지 않음
return true;
} else {
log.info("Failed login attempt for user: " + username); // 비밀번호를 로그에 기록하지 않음
return false;
}
}
// 추가: 비밀번호를 기록하지 않고, 실패한 로그인 시도를 제한하거나 모니터링할 수 있는 기능을 추가
private boolean isValidUser(String username, String password) {
// 사용자 인증 로직 구현 (예: 데이터베이스 확인)
return true; // 임시 코드
}
로그에 비밀번호를 제거/로그 메시지 간소화/로그메시지 내용 강화