설명
사용자가 제어하는 문자열을 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 {
"&": "&",
"<": "<",
">": ">",
'"': """,
"'": "'",
}[c];
});
}
function safeWithEscape(userInput) {
$("#container").html(escapeHTML(userInput)); // 이스케이프 처리 후 사용
}
설명:
- 변경 전: 신뢰할 수 없는 값을 HTML로 해석하는 API에 전달합니다. 현재 브라우저의 URL 프래그먼트는 읽을 때 퍼센트 디코딩되지 않으므로,
window.location.hash에 인코딩된 태그가 있다는 사실만으로 실행되는 것은 아닙니다. 별도 디코딩을 포함해 실제 HTML 값이 어떻게 만들어지는지 확인하세요. - 변경 후:
text()또는 HTML 본문용 이스케이프를 사용해 이 출력 위치에서 값을 텍스트로 표시합니다.