불완전한 출력 인코딩/이스케이프 (Improper Output Encoding/Escaping)

Improper Encoding or Escaping of Output

설명

자바스크립트의 $STR.replace('문자', '바꿀값')와 같이 문자열로 검색할 때는 첫 번째로 만나는 문자열만 변경합니다. 만약 이 기능을 보안 목적(예: 위험 문자의 이스케이프)으로 사용하면 나머지 동일한 위험 문자가 제대로 필터링되지 않아 우회 공격이 발생할 수 있습니다. 예를 들어, 단일 replace만 쓸 경우 여러 특수문자 중 첫 번째만 바뀌고 이후 값은 그대로 남아 공격자가 악의적으로 시스템을 조작할 가능성이 생깁니다.

잠재적 영향

  • 출력 데이터 변조 (출력 데이터 위변조): 모든 위험 요소가 변환되지 않아 공격자가 스크립트 삽입, SQL 인젝션 등으로 시스템을 공격할 수 있습니다.
  • 우회 공격 가능성 (필터 우회): 충분한 이스케이프가 안될 경우 필터링을 쉽게 우회할 수 있습니다.

해결 방법

  • 반복된 문자를 치환해야 한다면 정규표현식과 전역(g) 플래그로 모든 발생 위치를 처리하세요. 작은따옴표 치환만으로 SQL 인젝션을 방지하려 하지 말고, SQL에는 매개변수화된 쿼리를 사용하세요.
  • 출력 컨텍스트에 맞는 인코더를 사용하세요. HTML 마크업을 허용해야 한다면 DOMPurify 같은 정화 라이브러리를 사용하세요.
  • HTML 본문 텍스트에는 &, <, >, ", ' 등 필요한 문자를 HTML 엔터티로 인코딩하세요. 이 처리를 JavaScript, CSS, URL 등 다른 컨텍스트에 그대로 적용하지 마세요.

예시

변경 전

javascript
function escapeQuotes(s) {
  return s.replace("'", "''");
}

function escapeHtml(html) {
  return html.replace("<", "&lt;").replace(">", "&gt;");
}

변경 후

javascript
function escapeQuotes(s) {
  return s.replace(/'/g, "''"); // 모든 작은따옴표를 모두 치환
}

function escapeHtml(html) {
  return html.replace(/[&<>"']/g, (ch) => ({
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    '"': "&quot;",
    "'": "&#x27;",
  }[ch])); // HTML 본문 컨텍스트에 필요한 문자를 모두 인코딩
}

설명:

  • 변경 전: .replace("특수문자", ...) 방식은 해당 문자가 처음 등장할 때만 치환하고, 두 번째 이후로는 변경이 일어나지 않습니다. 출력 컨텍스트에 필요한 다른 문자도 함께 처리해야 합니다.
  • 변경 후: 정규표현식과 전역(g) 플래그를 사용해 문자열 내 모든 발생 위치를 처리하고, HTML 본문 컨텍스트에 필요한 문자를 엔터티로 변환합니다. 이렇게 하면 반복 등장 문자로 인한 우회를 예방할 수 있습니다.

참조