로그 인젝션 (Log Injection)

Log Injection

설명

로그 인젝션은 신뢰되지 않은 입력값을 그대로 로그에 기록할 때 발생합니다. 공격자는 개행 문자(\n, \r), 탭, ANSI 이스케이프, HTML 태그 등을 주입해 로그 라인을 분리하거나 새로운 로그처럼 보이게 만들 수 있습니다. 그 결과 실제 이벤트를 숨기거나 위조된 메시지를 섞어 운영자를 혼란스럽게 할 수 있으며, 웹 UI에서 로그를 렌더링하는 경우 XSS로 악용될 수 있습니다.

잠재적 영향

  • Log Forgery (로그 위조/오염): 개행 및 제어문자를 넣어 여러 줄을 생성해 새로운 이벤트처럼 보이게 하거나 원본 로그의 의미를 바꿀 수 있음.
  • Alert/Detection Evasion (경보·탐지 우회): SIEM/파서가 라인 기반으로 수집할 때 레코드를 깨뜨려 규칙 매칭·경보를 우회할 수 있음.
  • Incident Response Delay (사고 대응 지연): 위조된 로그로 분석이 어려워져 원인 파악과 대응이 늦어짐.
  • XSS in Log Viewer (로그 뷰어 XSS): HTML로 렌더링되는 콘솔/대시보드에서 스크립트가 실행될 수 있음.
  • Compliance/Audit Issues (감사 무결성 훼손): 감사 추적(로그 무결성)이 손상되어 규정 준수와 포렌식에 문제 발생.

해결 방법

  • 개행/제어문자 처리: 로그 형식에 맞게 \n, \r와 필요한 제어문자를 제거하거나 이스케이프하세요. 예: value.replace(/[\r\n]/g, '').
  • 고정 포맷 사용: console.log('%s', value)처럼 포맷 문자열을 고정하세요. %s 자체는 입력의 개행이나 제어문자를 제거하지 않으므로 별도 처리가 필요합니다.
  • 웹 로그 뷰어에서는 텍스트로 출력하거나 해당 HTML 컨텍스트에 맞게 인코딩하세요.
  • 길이 제한: 과도한 입력으로 로그 Flooding을 방지하기 위해 최대 길이 제한(예: 256자)을 적용하세요.
  • 공통 로깅 헬퍼: sanitizeForLog 같은 중앙화된 함수로 모든 입력을 정규화하고 재사용하세요.
  • 민감정보 최소화: 계정비밀번호, 토큰 등 민감값은 로그에 남기지 마세요.

예시

변경 전

javascript
const express = require('express');
const app = express();

app.get('/audit', (req, res) => {
  const agent = req.headers['user-agent']; // tainted
  const q = req.query.q; // tainted

  // BAD: 사용자 입력을 그대로 템플릿에 넣어 로그 기록
  console.info(`[AUDIT] agent=${agent} query=${q}`);

  res.send('ok');
});

app.listen(3001);

변경 후

javascript
const express = require('express');
const app = express();

function sanitizeForLog(v) {
  if (typeof v !== 'string') return v;
  // CR/LF 및 유니코드 줄 구분자 제거, 길이 제한
  const noCtl = v.replace(/[\r\n]/g, '').replace(/[\u2028\u2029]/g, '');
  return noCtl.length > 256 ? noCtl.slice(0, 256) + '…' : noCtl;
}

app.get('/audit', (req, res) => {
  const rawAgent = req.headers['user-agent'];
  const rawQ = req.query.q;
  const agent = sanitizeForLog(String(rawAgent || 'unknown'));
  const q = sanitizeForLog(String(rawQ || ''));

  // GOOD: 고정 포맷 + 사전 정규화된 값만 기록
  console.info('[AUDIT] agent=%s query=%s', agent, q);

  res.send('ok');
});

app.listen(3001);

설명:

  • 변경 전: 사용자 입력(agent, q)을 그대로 로그 메시지에 삽입했습니다. 공격자가 \n, \r, HTML 태그, ANSI 이스케이프 등을 주입하면 로그 라인이 분리되거나 위조 로그가 섞여 탐지/분석을 교란할 수 있습니다.
  • 변경 후: sanitizeForLog는 CR/LF와 유니코드 줄 구분자를 제거하고 길이를 제한합니다. 모든 제어문자나 HTML을 제거하는 것은 아닙니다. 고정 포맷과 함께 사용해 줄 단위 로그 위조를 줄이고, 터미널의 ANSI 처리와 웹 뷰어의 출력 인코딩은 별도로 적용해야 합니다.

참조