innerHTML을 통한 XSS와 방지 방법
사이트 간 스크립팅과 innerHTML의 안전한 대안 이해하기
innerHTML을 통한 XSS와 방지 방법은(는) CoddyKit의 무료 HTML Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 HTML Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. HTML Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
핵심 취약점
el.innerHTML = userInput은 문자열을 HTML로 구문 분석합니다. userInput에 <script> 태그나 이벤트 처리기 속성(onclick, onerror)이 포함되어 있으면 브라우저가 이를 해석하여 페이지에서 공격자가 제어하는 코드를 실행합니다.
흔한 이유
사용자 데이터를 HTML에 삽입하는 모든 코드(서버 템플릿, 클라이언트 측 렌더링)는 데이터가 이스케이프되지 않으면 XSS 위험이 있습니다. API 응답으로 innerHTML을 구성하는 단일 페이지 앱은 특히 취약하며, 해당 응답에 사용자 콘텐츠가 포함될 때 위험이 커집니다.
구체적인 예
div.innerHTML = `Welcome, ${user}`를 통해 설정한 사용자 이름 "Bob<img src=x onerror=alert(1)>"은 img 로드에 실패할 때 alert(1)을 실행합니다. 동일한 페이로드를 일반 텍스트(textContent 사용)로 처리하면 브라우저가 태그가 아닌 문자로만 인식하므로 안전합니다.
// VULNERABLE
div.innerHTML = `Hi, ${user.name}`;
// SAFE
div.textContent = `Hi, ${user.name}`;일반 텍스트에는 textContent 사용
textContent는 텍스트만 설정하므로 HTML 특수 문자가 태그가 아닌 리터럴 문자로 표시됩니다. 이는 대부분의 경우에 적합한 도구입니다. 텍스트가 아니라 마크업을 실제로 렌더링해야 할 때만 innerHTML로 전환하십시오.
구조에는 DOM 메서드 사용
사용자 데이터로 요소를 만들려면 createElement와 textContent를 사용하여 구성하십시오: const li = document.createElement("li"); li.textContent = name; ul.appendChild(li);. 결과 구조는 innerHTML로 만든 것과 동일하지만, 설계상 XSS로부터 안전합니다.
innerHTML을 반드시 사용해야 할 때
서버에서 생성된 신뢰할 수 있는 HTML(직접 만든 템플릿의 출력, 신뢰할 수 있는 편집기에서 정제된 서식 있는 텍스트)에는 innerHTML을 사용해도 괜찮습니다. 신뢰할 수 없는 출처의 데이터에는 정제 없이 직접 적용하지 마십시오.
DOMPurify로 서식 있는 텍스트 정제
사용자가 서식 있는 텍스트를 제출하는 경우(댓글 편집기, 마크다운 렌더링), innerHTML을 설정하기 전에 정제하십시오: el.innerHTML = DOMPurify.sanitize(richHtml). DOMPurify는 위험한 태그와 속성을 제거하면서 <b>, <em>, <a>와 같은 안전한 서식은 유지합니다.
insertAdjacentHTML에도 같은 위험이 있습니다
el.insertAdjacentHTML("beforeend", html)은 HTML 문자열을 구문 분석하므로 innerHTML과 동일한 XSS 공격 표면을 가집니다. 규칙도 같습니다. 사용자 데이터를 직접 전달하지 말고 정제하거나 DOM 메서드를 사용하십시오. document.write도 마찬가지이지만, 이제는 누구도 사용해서는 안 됩니다.
프레임워크의 기본 동작
React, Vue, Svelte, Angular는 모두 기본적으로 삽입된 텍스트를 이스케이프하므로 {name}은 안전합니다. 이들은 이스케이프를 우회하는 기능을 제공합니다(React의 dangerouslySetInnerHTML, Vue의 v-html). 이러한 기능은 동일한 XSS 위험을 가지므로 정제와 함께 신중하게 사용하십시오.
속성 삽입
속성 값도 공격 경로가 될 수 있습니다. url="javascript:alert(1)"인 <a href={url}>은 클릭할 때 실행됩니다. 사용자 입력을 href, src 또는 URL을 담는 다른 속성에 넣기 전에 URL 스킴별로 검증하십시오(http:, https:, mailto:, tel:만 허용).
신뢰할 수 있는 형식 정책
최신 브라우저는 신뢰할 수 있는 형식을 지원합니다. CSP를 require-trusted-types-for 'script'로 구성하면 innerHTML이 원시 문자열을 거부하고, 정책으로 감싼 값만 통과합니다. 이를 통해 개발자의 주의가 아니라 API 자체로 XSS를 방지할 수 있습니다.
다층 방어
어떤 단일 계층도 충분하지 않습니다. 서버에서 입력을 검증하고, 렌더링할 때 출력을 이스케이프하며, 삽입된 스크립트를 차단하는 CSP를 적용하고, 원시 문자열을 거부하는 신뢰할 수 있는 타입을 사용하며, innerHTML을 사용하는 모든 부분을 보안 검토로 확인하십시오. 계층화된 방어는 어느 한 계층에 버그가 있어도 견딜 수 있습니다.
이해도 확인
el.textContent = userInput은 XSS로부터 안전한데 el.innerHTML = userInput은 왜 위험합니까?
요약
사용자 입력에 innerHTML을 사용하는 것은 고전적인 XSS 공격 벡터입니다. 텍스트에는 textContent를 사용하고, 구조를 만들 때는 createElement+textContent를 사용하며, 서식 있는 HTML이 필요할 때는 DOMPurify를 사용하십시오. 속성 값에 사용할 URL 스킴을 검증하십시오. CSP와 신뢰할 수 있는 타입을 함께 적용하여 코드 검토에서 놓친 버그를 무력화하십시오. 최신 프레임워크는 기본적으로 이스케이프하므로, 안전하지 않은 우회 기능은 드물게 사용하고 반드시 검토하십시오.
자주 묻는 질문
“innerHTML을 통한 XSS와 방지 방법” 강의는 무료인가요?
네 — “innerHTML을 통한 XSS와 방지 방법” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 HTML Academy 강의 전체를 잠금 해제할 수 있습니다. HTML Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“innerHTML을 통한 XSS와 방지 방법”에서 뭘 배우나요?
사이트 간 스크립팅과 innerHTML의 안전한 대안 이해하기 브라우저에서 직접 실행하는 실습 코드로 HTML Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
HTML Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 HTML Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.
“innerHTML을 통한 XSS와 방지 방법” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 HTML Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 HTML Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 콘텐츠 보안 정책 meta http-equiv
- innerHTML을 통한 XSS와 방지 방법
- iframe 샌드박스 및 권한 정책
- HTTPS 및 하위 리소스 무결성