출력 인코딩 또는 이스케이프 미흡 (Improper Output Encoding or Escaping)

Improper Encoding or Escaping of Output

설명

템플릿 엔진(Mustache 등)에서 기본 HTML 이스케이프 함수를 무력화하면, HTML 특수 문자가 자동 이스케이프되지 않아 악의적인 스크립트가 그대로 출력될 수 있습니다. Mustache.js에서는 Mustache.escape를 사용자 정의 함수로 덮어쓸 수 있으며, 이를 입력을 그대로 반환하는 함수로 바꾸면 XSS(Cross-Site Scripting) 공격으로 이어질 수 있습니다.

잠재적 영향

  • XSS 공격 가능 (크로스사이트 스크립팅): 공격자가 악의적인 스크립트를 삽입해 사용자의 브라우저에서 실행될 수 있습니다.
  • 정보 탈취: 사용자의 쿠키, 세션 정보 등이 탈취될 수 있습니다.
  • 사이트 변조 또는 서비스 신뢰도 저하: 웹페이지가 공격자에 의해 변조될 수 있습니다.

해결 방법

  • HTML 텍스트에 값을 출력할 때 템플릿의 기본 이스케이프를 유지하세요.
  • 입력을 그대로 반환하는 함수로 Mustache.escape를 덮어쓰지 마세요.
  • URL, JavaScript, CSS 등 다른 출력 문맥은 해당 문맥에 맞게 검증·인코딩하세요. HTML 이스케이프만으로 모든 문맥이 보호되지는 않습니다.

예시

변경 전

javascript
const Mustache = require('mustache');

// BAD: Mustache의 HTML 이스케이프 함수를 입력 그대로 반환하도록 덮어씀
Mustache.escape = function(text) {
  return text;
};

const unsafeTemplate = '<div>{{userInput}}</div>';
const html = Mustache.render(unsafeTemplate, { userInput: req.query.text });

변경 후

javascript
const Mustache = require('mustache');

// GOOD: Mustache의 기본 이스케이프 동작을 그대로 사용
const safeTemplate = '<div>{{userInput}}</div>';
const html = Mustache.render(safeTemplate, { userInput: req.query.text });

설명:

  • 변경 전: Mustache.escape를 입력 그대로 반환하도록 덮어쓰면, 템플릿에 삽입된 사용자 입력값이 HTML로 이스케이프되지 않아 악성 스크립트가 그대로 브라우저에 삽입되고 실행될 수 있습니다.
  • 변경 후: Mustache의 기본 이스케이프 동작을 유지하면, 이 예제의 HTML 텍스트 위치에 들어갈 특수 문자가 이스케이프됩니다. 변경 전·후는 별도의 실행을 가정하며, 이미 덮어쓴 전역 함수를 단순히 다시 require한다고 복구되지는 않습니다.

참조