회원가입 | 고객센터 |
DESIGNONEX
디자인원엑스
Q&AN
지식공유
공지사항
DX마켓
통계
로그인 회원가입
고객센터

DX Security — Log Injection 보안 플러그인

D DX관리자
2026.09.05 18:45 8 0



DX Security — Log Injection 방어 v1.0.0 안내서

PHP 5.6+ · IIS / Apache / Nginx 완전 호환 코어 dx_log() 수정 없음 — 보완 API 제공



목차

  1. Log Injection이란 무엇인가
  2. DXCMS 코어 로그 방식 분석
  3. 이 플러그인의 역할
  4. 설치 방법
  5. 방어층 상세 설명
  6. 보안 로그 형식
  7. 보안 강점 요약
  8. 개발자 API 가이드


1. Log Injection이란 무엇인가

공격자가 사용자 입력값을 로그에 삽입하여 가짜 로그를 생성하거나, 기존 로그를 위조·오염·은폐하는 공격입니다.

공격 시나리오:

① CRLF Injection:
  username = admin\r\nLOGIN_SUCCESS

  취약한 로그:
    LOGIN_FAILURE username=admin
    LOGIN_SUCCESS            ← 공격자가 삽입

② JSON Injection:
  username = "},"result":"SUCCESS

  취약한 JSON 로그:
    {"event":"LOGIN_FAILURE","user":"},"result":"SUCCESS"}
    → JSON 구조 파괴, result를 SUCCESS로 위조

③ Log Viewer XSS:
  username = <script>alert(document.cookie)</script>
  → 로그 → 관리자 화면 → XSS 실행

④ 민감정보 노출:
  Exception: password=qwerty123 token=eyJhbGci...
  → 로그 파일에 원문 저장 → 로그 유출 시 계정 탈취


핵심 원칙

사용자 입력은 로그의 데이터일 수 있지만
로그의 구조·이벤트·심각도·시간을 결정할 수 없어야 한다.

위험:
  $line = "[" . date() . "][LOGIN_FAILURE] " . $userInput;  // CRLF Injection
  file_put_contents($log, $line);

안전:
  dx_security_log('LOGIN_FAILURE', array('input' => $userInput));
  // 자동 정규화 + 구조화 + 마스킹


2. DXCMS 코어 로그 방식 분석

// 코어 dx_log()
function dx_log($message, $level = 'info')
{
    // ... 레벨 확인 ...
    $line = '[' . date('Y-m-d H:i:s') . '][' . strtoupper($level) . ']'
          . ($caller ? '[' . $caller . ']' : '')
          . ' ' . $message;  // ← $message에 사용자 입력이 들어오면 위험

    @file_put_contents(DX_DATA . '/error.log', $line . PHP_EOL, FILE_APPEND | LOCK_EX);
}


11~19번 보안 플러그인의 로그 방식:

// 취약할 수 있는 기존 방식
$line = sprintf("[%s][AUTH:%s][IP:%s]... %s\n",
    date(...), $type, $ip, $msg);  // $msg에 사용자 입력 포함 가능
file_put_contents(DX_ROOT . '/data/security.log', $line, FILE_APPEND | LOCK_EX);
항목 코어/기존 방식 평가
CRLF 제거 없음
민감정보 마스킹 없음
구조화 로그 없음
Log Rate Limit 없음
Request ID 없음
Log Integrity 없음
Log Viewer XSS 없음


3. 이 플러그인의 역할

코어 dx_log()를 대체하지 않고 보완 API를 제공합니다. 새로 작성하는 플러그인 코드에서 dx_security_log()를 사용하면 자동으로 모든 방어가 적용됩니다.



4. 설치 방법

(DXCMS 루트)/
└── plugins/
    └── dx-security-log/
        ├── manifest.php
        └── plugin.php
관리자 → 플러그인 → dx-security-log → 활성화


5. 방어층 상세 설명


LI1. CRLF / 제어문자 / ANSI Escape 제거

제거 대상:
  \r\n, \r, \n  → 공백으로 치환 (Log Splitting 방어)
  \x00 (NULL)   → 제거 (Log Truncation 방어)
  ANSI Escape   → 제거 (터미널 제어 방어)
  \x01~\x1f     → 제거 (제어문자 방어)
  \t (탭)       → 공백으로 치환

처리 순서: 모든 사용자 입력에 적용


LI2. 민감정보 자동 마스킹

탐지 후 마스킹 대상:
  password=qwerty123      → password=qw********23
  token=eyJhbGci...       → token=ey******...
  secret=abc123           → secret=ab****23
  api_key=key_xxx         → api_key=ke****xx
  authorization=Bearer... → authorization=Be******er
  cookie=session_id=...   → cookie=se****...

마스킹 형식:
  앞 2자리 + **** + 뒤 2자리


LI3. 구조화 로그 (Structured Logging)

기존 방식:
  [2026-09-03 09:00:01][AUTH:LOGIN_FAILED]... login_id=admin reason=WRONG_PASSWORD

구조화 방식:
  ts=2026-09-03 req=REQ-a1b2c3 event=AUTH:LOGIN_FAILED ip=45.33.x.x uid=0
  method=POST uri=/auth/login ua="Mozilla/5.0..." login_id=admin reason=WRONG_PASSWORD

필드 분리:
  ts         → 서버 시간 (사용자 변경 불가)
  req        → Request ID (요청당 고유값)
  event      → 이벤트 타입 (서버에서 결정)
  ip         → Canonical Client IP (Proxy Trust 적용)
  uid        → 로그인 사용자 ID
  method/uri → 요청 정보
  ua         → User-Agent (512자 제한)
  [추가 필드] → CRLF 제거 + 마스킹 후 저장


LI4. Log Rate Limit

정책:
  같은 IP + Event 조합으로 60초에 50회 초과 시 억제

중요 예외:
  첫 번째 이벤트: 항상 기록
  임계치 초과 첫 번째: 경고 로그 후 억제 시작
  → 최초 이벤트와 초과 경고는 반드시 보존

저장: data/cache/lirate_*.tmp (TTL 자동 만료)


LI5. 필드 길이 제한

필드 최대 길이
이벤트 타입 64자
일반 필드 255자
메시지 2,048자
User-Agent 512자
URI 200자

초과 시: ...(truncated) 접미사 추가



LI6. Log Viewer XSS 방어

관리자 로그 조회  자동 헤더 추가:
  X-Content-Type-Options: nosniff
  Cache-Control: no-store, no-cache

로그 출력  HTML 이스케이프 API 제공:
  dx_log_escape_html($logValue)
   htmlspecialchars(ENT_QUOTES, UTF-8)


LI7. Log Integrity — HMAC 검증

보안 중요 로그에 HMAC 태그 포함 가능:
  dx_security_log('CRITICAL_EVENT', $fields, true)

로그 행 예시:
  ts=2026-09-03 ... event=ADMIN_DELETE ... hmac=a1b2c3d4e5f6g7h8

변조 확인:
  dx_log_verify_integrity($logLine)
  → true  (무결성 확인)
  → false (변조 또는 태그 없음)

HMAC 키: DX_SECRET_KEY 설정값 사용


LI8. Request ID 추적

요청당 고유 ID 자동 생성:
  REQ-a1b2c3d4e5f6

같은 요청의 모든 로그에 동일 ID:
  REQ-a1b2c3 AUTH:LOGIN_FAILED
  REQ-a1b2c3 RATE_LIMIT_EXCEEDED
  REQ-a1b2c3 AUTHZ:ACCESS_DENIED

공격자가 로그를 섞어도 요청 흐름 추적 가능


6. 보안 로그 형식

# 구조화 로그 예시
ts="2026-09-03 09:00:01" req=REQ-a1b2c3 event=AUTH:LOGIN_FAILED
ip=45.33.x.x uid=0 method=POST uri=/auth/login
ua="Mozilla/5.0 (Windows NT 10.0)" login_id=admin reason=WRONG_PASSWORD

# HMAC 태그 포함 (integrity=true)
ts="2026-09-03 14:22:10" req=REQ-d4e5f6 event=ADMIN:CONFIG_CHANGED
ip=121.131.x.x uid=1 method=POST uri=/admin/config
key=security.enabled value=false hmac=a1b2c3d4e5f60000

# 민감정보 마스킹
ts="2026-09-03 16:45:03" req=REQ-g7h8i9 event=LOG:ERROR
ip=58.29.x.x uid=0 method=POST uri=/auth/login
message="Login failed password=qw****23 for user admin"

# Log Viewer 접근 감사
ts="2026-09-03 20:11:44" req=REQ-j0k1l2 event=LOG_VIEWER_ACCESS
ip=121.131.x.x uid=1 method=GET uri=/admin/security/log


7. 보안 강점 요약

공격 결과 방어 레이어
CRLF Injection CR/LF → 공백 치환 LI1
Log Splitting CRLF 제거 LI1
ANSI Escape 제거 LI1
민감정보 노출 자동 마스킹 LI2
JSON 구조 파괴 구조화 필드 분리 LI3
Log DoS 50회/60초 제한 LI4
과도한 로그 길이 필드별 최대 길이 LI5
Log Viewer XSS HTML 이스케이프 API + 헤더 LI6
로그 변조 탐지 HMAC 검증 LI7
로그 흐름 추적 Request ID LI8
정상 로그 기록 영향 없음


8. 개발자 API 가이드

구조화 보안 로그 기록

// 기본 사용
dx_security_log('AUTH:LOGIN_FAILED', array(
    'login_id' => $loginId,     // 자동 CRLF 제거
    'reason'   => $reason,      // 자동 마스킹 적용
));

// HMAC Integrity 포함 (중요 이벤트)
dx_security_log('ADMIN:CONFIG_CHANGED', array(
    'key'   => $configKey,
    'value' => $newValue,
), true);  // 세 번째 인자 true = HMAC 태그 포함


로그 필드 수동 정규화

// 사용자 입력을 로그에 포함하기 전 정규화
$safeInput = dx_log_sanitize($userInput, 100);  // 100자 제한
$line = "event=CUSTOM field=" . $safeInput;


민감정보 마스킹

$msg = "Login failed password=$userPassword for user $username";
$masked = dx_log_mask($msg);  // password 자동 마스킹


Log Viewer HTML 이스케이프

// 관리자 화면에서 로그 출력 시
foreach ($logLines as $line) {
    echo '<pre>' . dx_log_escape_html($line) . '</pre>';
    // htmlspecialchars 자동 적용 → XSS 방어
}


HMAC Integrity 검증

// 로그 행이 변조되지 않았는지 확인
$logLine = 'ts="2026-09-03" ... event=ADMIN_DELETE ... hmac=a1b2c3d4';
if (dx_log_verify_integrity($logLine)) {
    echo '무결성 확인됨';
} else {
    echo '변조 또는 태그 없음';
}


Request ID 활용

// 현재 요청의 ID
$reqId = dx_log_request_id();  // REQ-a1b2c3d4e5f6

// 여러 로그에 같은 Request ID 포함
dx_security_log('STEP_1', array('req_ref' => $reqId));
dx_security_log('STEP_2', array('req_ref' => $reqId));

DX Security — Log Injection 방어 v1.0.0 — DesignOneX https://designonex.com
 

라이선스

디자인원엑스 라이선스 참고
https://designonex.com/notice/view/1787577858493247

 

첨부파일 1개 회원전용

댓글0

로그인 후 댓글을 작성할 수 있습니다.
Plugin 58
45
전체 회원
1,396
전체 게시글
2,748
전체 댓글
85
오늘 방문
53,603
전체 방문
0
현재 접속
인기글 7일 이내
최신글
최신댓글
내 플레이리스트
플레이리스트가 비어있습니다
스튜디오 게시판에서
플레이리스트에 담기 버튼을
눌러보세요
목록
목록