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

Cross-site Scripting (XSS)

설명

크로스 사이트 스크립팅(XSS) 취약점은 사용자의 입력값이 적절하게 인코딩되지 않은 상태로 HTML 템플릿 문자열에 포함될 때 발생합니다. 이런 경우, 공격자가 악의적인 스크립트나 HTML 태그를 입력값에 삽입할 수 있으며, 이 코드가 사용자 브라우저에서 실행되어 정보 유출이나 세션 탈취 등의 피해가 발생할 수 있습니다.

잠재적 영향

  • 개인정보 유출: 스크립트가 읽을 수 있는 쿠키, 세션 토큰, 입력 정보가 탈취될 수 있습니다.
  • 사이트 변조: 공격자가 악의적인 HTML/스크립트를 삽입하여 사이트의 정상적인 동작을 방해하거나 피싱을 유도할 수 있습니다.

해결 방법

  • HTML 본문에 텍스트를 삽입할 때는 문맥에 맞는 HTML 인코딩이나 템플릿의 자동 이스케이프를 사용하세요.
  • 마크업이 필요 없다면 innerHTML 대신 textContent를 사용하세요. setAttribute는 고정된 비실행 속성에만 사용하고 URL 값은 스킴과 목적지를 별도로 검증하세요.
  • HTML 마크업을 허용해야 한다면 DOMPurify 같은 HTML 정화 도구로 허용할 태그와 속성을 제한하세요. 정화는 텍스트 인코딩과 다르며, 일반 HTML 이스케이프를 JavaScript나 CSS 문맥에 재사용하면 안 됩니다.

예시

변경 전

javascript
const userInput = '<img src="x" onerror="alert(1)">'; // 악의적인 입력
const message = `<div>${userInput}</div>`;
document.body.innerHTML = message;

변경 후

javascript
function escapeHtml(str) {
  return str.replace(/[&<>'"]/g, function (c) {
    return {
      "&": "&amp;",
      "<": "&lt;",
      ">": "&gt;",
      "'": "&#39;",
      '"': "&quot;",
    }[c];
  });
}
const userInput = '<img src="x" onerror="alert(1)">'; // 악의적인 입력
const message = `<div>${escapeHtml(userInput)}</div>`;
document.body.innerHTML = message;

설명:

  • 변경 전: userInput 변수에 들어있는 악의적인 태그나 스크립트가 HTML 템플릿 문자열에 그대로 삽입되어, 브라우저에서 실행될 수 있습니다.
  • 변경 후: escapeHtml 함수를 통해 사용자 입력값을 HTML로 인코딩하여, 태그나 스크립트가 실행되는 것을 방지합니다. 이 예시의 HTML 본문에서 입력한 값이 태그로 해석되지 않고 텍스트로 출력됩니다.

참조