크로스 사이트 스크립팅(XSS)

Cross-site Scripting (XSS)

설명

사용자가 제어하는 문자열을 jQuery의 html(), append(), prepend(), wrap(), wrapInner(), wrapAll(), before(), after()에 HTML로 전달하면 악성 마크업이 실행될 수 있습니다. globalEval()은 문자열을 코드로 실행하며, getScript()는 지정한 URL의 스크립트를 가져와 실행하므로, 각각 코드와 URL의 신뢰성을 별도로 확인해야 합니다.

잠재적 영향

  • 개인정보 유출: 악성 스크립트 실행을 통해 쿠키나 인증 정보가 유출될 수 있습니다.
  • 세션 하이재킹: 공격자가 사용자의 세션을 탈취하여 권한을 획득할 수 있습니다.
  • 피싱 또는 사기 페이지 유도: 악의적인 HTML/JS 코드로 사용자를 속일 수 있습니다.

해결 방법

  • 텍스트는 text()로 출력하고, 폼 값은 val()처럼 해당 목적에 맞는 API에 전달하세요.
  • HTML 본문에 넣을 텍스트는 인코딩하고, 허용해야 하는 실제 HTML은 검증된 정화 도구로 제한하세요.
  • globalEval()에 외부 입력을 전달하지 말고, getScript()에는 신뢰할 수 있는 고정 스크립트 URL만 사용하세요. HTML 이스케이프는 코드 실행이나 스크립트 URL 검증을 대신하지 않습니다.

예시

변경 전

javascript
// 취약: 사용자 입력값이 DOM 조작 함수에 직접 전달
function vulnerable(userInput) {
  $("#container").html(userInput); // XSS 취약점
}

// 또 다른 예시
const hash = window.location.hash;
$("div").append(hash); // HTML로 해석되는 실제 값에 따라 위험이 달라짐

변경 후

javascript
// 안전 적용: 텍스트 출력에는 text() 사용
function safe(userInput) {
  $("#container").text(userInput); // 안전
}

// 또는 HTML 이스케이프 처리 후 사용
function escapeHTML(str) {
  return String(str).replace(/[&<>'"]/g, function (c) {
    return {
      "&": "&amp;",
      "<": "&lt;",
      ">": "&gt;",
      '"': "&quot;",
      "'": "&#39;",
    }[c];
  });
}

function safeWithEscape(userInput) {
  $("#container").html(escapeHTML(userInput)); // 이스케이프 처리 후 사용
}

설명:

  • 변경 전: 신뢰할 수 없는 값을 HTML로 해석하는 API에 전달합니다. 현재 브라우저의 URL 프래그먼트는 읽을 때 퍼센트 디코딩되지 않으므로, window.location.hash에 인코딩된 태그가 있다는 사실만으로 실행되는 것은 아닙니다. 별도 디코딩을 포함해 실제 HTML 값이 어떻게 만들어지는지 확인하세요.
  • 변경 후: text() 또는 HTML 본문용 이스케이프를 사용해 이 출력 위치에서 값을 텍스트로 표시합니다.

참조