브라우저에 Element.setHTML() 이라는 새로운 메서드가 들어왔다.
역할은 단순하다.
“문자열 HTML을 파싱 + Sanitizing 해서, XSS-safe한 DOM 서브트리로 삽입하는 메서드”
실제 의도는 더 명확하다.
“사용자가 제공한 HTML 문자열을 넣을 때
innerHTML대신 쓰는 안전한 API”
단, 실험적(Experimental) 기능이고, 브라우저 지원도 아직 제한적이기 때문에, 실제 프로덕션에서는 반드시 호환성 테이블을 확인해야 한다.
element.setHTML(input);
element.setHTML(input, options);
input: 문자열 HTMLoptions (선택)sanitizer:Sanitizer 인스턴스SanitizerConfig 객체"default" 문자열undefined (반환값 없음)TypeError가 발생하는 경우:
options.sanitizer가 비정상 SanitizerConfig 인 경우allowed와 removed(혹은 allow/remove 계열 옵션)를 동시에 섞어쓴 설정"default" 가 아닌 값인 경우Sanitizer, SanitizerConfig, 문자열, 어느 쪽에도 해당하지 않는 타입인 경우setHTML()은 대략 다음 순서로 동작한다고 볼 수 있다.
<table> 밖에 있는 <col> 같은 것핵심: “항상 XSS-safe를 우선” 한다.
문자열에 아래 요소들이 있어도, 최종 DOM에는 들어가지 않는다.
<script><frame><iframe><embed><object><use>onclick, onmouseover 등)중요한 점:
sanitizer로 저 요소들을 “허용”하더라도,
setHTML()은 강제로 제거한다.
이는 내부적으로 Sanitizer.removeUnsafe() 를 항상 거치는 것과 같다.
options.sanitizer를 생략하면 기본 Sanitizer 설정을 사용한다.
target.setHTML(unsafeString);
기본 설정의 의미:
자세한 구성은 Sanitizer() 생성자 문서를 기준으로 한다.
const sanitizer = new Sanitizer({
elements: ["div", "p", "button", "script"], // script를 허용하려 해도…
});
target.setHTML(unsafeString, { sanitizer });
script를 허용하도록 구성됐지만,setHTML()은 추가로 XSS-unsafe 요소를 제거 하므로script는 결국 DOM에 삽입되지 않는다.target.setHTML(unsafeString, {
sanitizer: {
removeElements: ["div", "p", "button", "script"],
},
});
SanitizerConfig를 직접 넘기면, 내부적으로 Sanitizer를 생성해서 사용removeElements 등을 이용해 요소 제거 정책을 커스터마이징innerHTML은 단순 문자열 파서 + DOM 삽입 메서드다.
element.innerHTML = userInput; // XSS risk!
“사용자 제공 HTML을 삽입해야 한다면, 가능하면
innerHTML대신setHTML()을 쓰라.”
특히:
Element.setHTMLUnsafe()라는 메서드도 언급된다.setHTML()을 쓰라는 것이 권장 사항이다.// 1) 위험한 문자열
const unsafe = "abc <script>alert(1)</script> def";
// 2) 대상 요소
const target = document.getElementById("target");
// 3) 기본 sanitizer 사용
target.setHTML(unsafe);
// 결과: <script> 제거된 문자열만 삽입
// Custom Sanitizer: div, p, button, script 허용이라고 설정했지만
const sanitizer1 = new Sanitizer({
elements: ["div", "p", "button", "script"],
});
target.setHTML(unsafe, { sanitizer: sanitizer1 });
// → script는 XSS-unsafe라서 여전히 제거됨
// Config를 inline으로 전달해서 특정 요소를 제거하도록 설정
target.setHTML(unsafe, {
sanitizer: { removeElements: ["div", "p", "button", "script"] },
});
// → div/p/button/script 모두 제거 + 그 외 unsafe도 제거
<button id="buttonDefault" type="button">Default</button>
<button id="buttonAllowScript" type="button">allowScript</button>
<button id="reload" type="button">Reload</button>
<div id="target">Original content of target element</div>
const unsanitizedString = `
<div>
<p>Paragraph to inject into shadow DOM.
<button>Click me</button>
</p>
<script src="path/to/a/module.js" type="module"></script>
<p data-id="123">Para with <code>data-</code> attribute</p>
</div>
`;
const target = document.querySelector("#target");
const logElement = document.getElementById("log"); // 예: 로그 출력 영역
const reload = document.querySelector("#reload");
reload.addEventListener("click", () => document.location.reload());
const defaultSanitizerButton = document.querySelector("#buttonDefault");
defaultSanitizerButton.addEventListener("click", () => {
target.setHTML(unsanitizedString);
logElement.textContent =
"Default sanitizer: remove script element, onclick attribute, data- attribute\n\n";
log(`\nunsanitized: ${unsanitizedString}`);
log(`\n\nsanitized: ${target.innerHTML}`);
});
효과:
<script> 제거onclick 속성 제거data-id 속성도 제거 (기본 설정 기준, unsafe로 분류)const allowScriptButton = document.querySelector("#buttonAllowScript");
allowScriptButton.addEventListener("click", () => {
const sanitizer1 = new Sanitizer({
elements: ["div", "p", "script"],
});
target.setHTML(unsanitizedString, { sanitizer: sanitizer1 });
logElement.textContent =
"Sanitizer: {elements: ['div', 'p', 'script']}\n Script removed even though allowed\n";
log(`\nunsanitized: ${unsanitizedString}`);
log(`\n\nsanitized: ${target.innerHTML}`);
});
효과:
script를 허용하지만setHTML()이 XSS-unsafe로 판단해 <script>는 여전히 제거data-id 는, 이 경우엔 custom sanitizer 설정 상 허용될 수 있다setHTML()은 항상 자체적으로 sanitize를 수행한다.요약:
“Trusted Types는
innerHTML/insertAdjacentHTML류에 대한 보안 레이어고,
setHTML()은 애초에 XSS-safe 설계라 별도의 Trusted Types 검증을 하지 않는다.”
setHTML()은 “Experimental” 로 명시되어 있다.innerHTML + 별도 Sanitizer 라이브러리 (DOMPurify 등) 조합을 고려실무 가이드라인:
setHTML() 적극 테스트 가능Element.setHTML()은 XSS-safe한 innerHTML 대체 API다.<script>, <iframe>, <object>, <embed>, <use>, 이벤트 핸들러 속성 등은 항상 제거된다.Sanitizer / SanitizerConfig 옵션으로 세부 정책을 설정할 수 있지만,innerHTML 대신 setHTML() 사용을 권장.