[OWASP TOP 10] A09-Security Logging and Monitoring Failures

Tamszero·2024년 11월 22일

이비전

목록 보기
11/12

A09-security Logging and Monitoring Failures

: 애플리케이션의 보안 이벤트를 적절히 기록하고 이를 실기간으로 모니터링하지 않아 발생하는 위험

취약점 발생 케이스

  1. 중요 이벤트를 로깅하지 않은 경우
  2. 불충분한 로깅 정보
    • 기록된 로그가 불완전하거나 추적 가능성을 낮추는 방식으로 저장되는 경우
  3. 실시간 모니터링 부족
    • 로그 데이터를 실시간으로 분석하지 않아 의심스러운 활동이나 침입을 신속히 감지하지 못하는 경우
  4. 적절한 경고 메커니즘 부재
    • 의심스러운 활동에 대해 알림 시스템이 없거나 잘못 설정된 경우
  5. 로그 보호 미비
    • 로그 데이터가 조작, 삭제 또는 무단 접근에 취약한 경우

예방방법

개발자는 애플리케이션의 위험에 따라 다음 제어 중 일부 또는 전부를 구현해야한다.

  1. 모든 로그인, 액세스 제어 및 서버 측 입력 검증 실패를 충분한 사용자 컨텍스트와 함께 기록하여 의심스럽거나 악의적인 계정을 식별하고 지연된 포렌식 분석을 허용할 만큼 충분한 시간동안 보관할 수 있는지 확인함
  2. 로그 관리 솔루션에서 쉽게 사용할 수 있는 형식으로 로그가 생성되는지 확인
  3. 로그 또는 모니터링 시스템에 대한 주입이나 공격을 방지하기 위해 로그 데이터가 올바르게 인코딩 되었는지 확인
  4. 고가 거래에는 변조나 삭제를 방지하기 위한 무결성 제어를 통해 감사 추적을 실시해야함 (추가 전용 데이터베이스 테이블 포함)
  5. DevSecOps 팀은 의심스러운 활동을 감지하고 신속하게 대응할 수 있도록 효과적인 모니터링과 경고 시스템을 구축해야함
  6. NIST(National Institute of Standards and Technology) 800-61r2 이상과 같은 사고 대응 및 복구 계획을 수립하거나 채택함

CWE-778 : 불충분한 로깅

다음은 사용자를 인증하려고 시도하는 코드이다. 로그인 실패시 재시도를 하도록 한다. 하지만 실패한 로그인은 기록되지 않으며 공격자가 프로그램을 무차별 대입하려고 시도한 기록이 되지 않는 문제점이 있다.

** 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();
}

CWE-117 : 로그에 대한 부적절한 출력 중화

로그 출력 시 출력 중립화를 올바르게 수행하지 않아서 발생하는 보안 취약점
출력 중립화란?

  • 사용자 입력 데이터를 출력 목적에 맞게 변환하거나 필터링하여, 악성코드나 특수문자가 애플리케이션의 정상 동작을 방해하지 않도록 처리하는 과정

다음 웹 애플리케이션 코드는 요청 객체에서 정수 값을 읽으려고 시도한다. ParseInt 호출이 실패하면 입력은 무슨 일이 일어났는지 나타내는 오류 메시지와 함께 기록된다.

** Bad code **

String val = request.getParameter("val");
try {

int value = Integer.parseInt(val);
}
catch (NumberFormatException) {
log.info("Failed to parse val = " + val);
}
...

이 코드의 문제점

  • 로그 출력시 사용자 입력값의 검증 부족
    - 입력값에 포함된 특수 문자가 제대로 처리되지 않고 로그에 그대로 기록함
    - %0a → 줄바꿈, %3d → =와 같은 URL 인코딩된 문자들이 로그 출력 시 디코딩되어 잘못된 로그 형식을 유발함
  • 로그 메시지 중립화 미적용
    - 로그 기록전에 특수 문자나 잠재적 악성 입력값을 escape 하거나 filtering X

** 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); // 안전하게 로그 기록
}

CWE-223 : 보안 관련 정보의 생략

보안 관련 정보(실패한 인증 시도, 권한 부족 오류)가 로그에 기록되지 않거나 불완전하게 기록되었을 때 발생하는 취약점

다음은 의심스러운 여러 로그인 시도를 기록하는 코드이다

** 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') );
				}
		}
}

이 코드의 문제점

  • 로그 누락 발생
    • 실패한 모든 로그인 시도가 기록되지 않음
    • 실패 횟수가 5 이하인 경우는 로그에 남지 않으므로, 초기 공격 징후를 놓칠 수 있음
  • 공격자의 우회 가능성
  • 보안 관리의 어려움

** 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);
        }
    }
}

모든 실패한 로그인 시도를 기록/로그의 민감한 정보 보호/실패 임계값 초과 시 경고로그 추가

CWE-532 : 로그 파일에 민감한 정보 삽입

민감한 정보를 로그에 기록하여 정보 노출 위험을 초래하는 문제를 다룸.
애플리케이션이 동작 중 발생하는 이벤트를 기록하기 위해 로그를 사용하는 경우, 의도치 않게 민감한 정보(예: 비밀번호, 세션토큰, 개인 식별정보)를 포함시키면 보안 위협으로 이어질 수 있음

다음은 사용자가 입력한 비밀번호를 로그에 기록하는 코드 예시이다.

** 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; // 임시 코드
}

로그에 비밀번호를 제거/로그 메시지 간소화/로그메시지 내용 강화

0개의 댓글