Element: setHTML() ã¡ã½ãã
å©ç¨å¯è½æ§ã¯éå®ç
ãã®æ©è½ã¯ãã¼ã¹ã©ã¤ã³ã§ã¯ããã¾ãããæãåºã使ç¨ããã¦ãããã©ã¦ã¶ã¼ã®ä¸é¨ã§åä½ãã¾ããã
Want more browser support for this feature? Tell us why.
Experimental: ããã¯å®é¨çãªæ©è½ã§ãã
æ¬çªã§ä½¿ç¨ããåã«ãã©ã¦ã¶ã¼äºææ§ä¸è¦§è¡¨ããã§ãã¯ãã¦ãã ããã
setHTML() 㯠Element ã¤ã³ã¿ã¼ãã§ã¤ã¹ã®ã¡ã½ããã§ãHTML ã®æååãæ§æè§£æã»ãµãã¿ã¤ãºã㦠DocumentFragment ã«å¤æããããè¦ç´ ã®ãµãããªã¼ã¨ã㦠DOM ã«æ¿å
¥ãããXSS å¯¾çæ¸ã¿ã®å®å
¨ãªæ¹æ³ãæä¾ãã¾ãã
æ§æ
setHTML(input)
setHTML(input, options)
弿°
input-
æååã§ããµãã¿ã¤ãºããè¦ç´ ã«æ¿å ¥ããã HTML ãå®ç¾©ãã¾ãã
optionsçç¥å¯-
以ä¸ã®ãªãã·ã§ã³å¼æ°ãæã¤ãªãã·ã§ã³ãªãã¸ã§ã¯ãã§ãã
sanitizer-
Sanitizerã¾ãã¯SanitizerConfigãªãã¸ã§ã¯ãã§ãå ¥åã®ã©ã®è¦ç´ ã許å¯ããããåé¤ããããããããå®ç¾©ãã¾ããæåå"default"ã§æ¢å®ã®æ§æã«ãªãã¾ãã ä¸è¬çã«ãè¨å®ãåå©ç¨ããå ´åãSanitizerConfigãããSanitizerã®æ¹ãå¹ççã§ãããã¨ãæå¾ ããã¾ãã æå®ããªãã£ãå ´åãæ¢å®ã®ãµãã¿ã¤ã¶ã¼è¨å®ã使ç¨ããã¾ãã
è¿å¤
ãªã (undefined)ã
ä¾å¤
TypeError-
options.sanitizerã«æ¬¡ã®ãããªãã®ã渡ãããå ´åã«ä¾å¤ãçºçãã¾ãã- æ£è¦åããã¦ããªã
SanitizerConfigï¼"allowed" 㨠"removed" ã®ä¸¡æ¹ã®è¨å®ãå«ããã®ï¼ - å¤ã
"default"ã§ã¯ãªãæåå SanitizerãSanitizerConfigãæååã®ã©ãã§ããªãå¤ã
- æ£è¦åããã¦ããªã
解説
setHTML() ã¡ã½ããã¯ãHTML ã®æååãæ§æè§£æã»ãµãã¿ã¤ãºã㦠DocumentFragment ã«å¤æããããè¦ç´ ã®ãµãããªã¼ã¨ã㦠DOM ã«æ¿å
¥ãããXSS å¯¾çæ¸ã¿ã®å®å
¨ãªæ¹æ³ãæä¾ãã¾ãã
setHTML() ã¯ãç¾å¨ã®è¦ç´ ã®ã³ã³ããã¹ãã§ä¸æ£ãªè¦ç´ ï¼ä¾ï¼<table> è¦ç´ ã®å¤ã«ãã <col> è¦ç´ ï¼ã HTML å
¥åæååããé¤å»ãã¾ãã
ãã®å¾ããµãã¿ã¤ã¶ã¼è¨å®ã§è¨±å¯ããã¦ããªã HTML ã¨ã³ãã£ãã£ãåé¤ããããã« XSS 対çä¸å®å
¨ã§ãªãè¦ç´ ã屿§ãé¤å»ãã¾ãããããã¯ãµãã¿ã¤ã¶ã¼è¨å®ã§ã§ãããã©ããã«ãããããé¤å»å¯¾è±¡ã¨ãªãã¾ãã
options.sanitizer 弿°ã§ãµãã¿ã¤ã¶ã¼ã®æ§æãæå®ããã¦ããªãå ´åãsetHTML() ã¯æ¢å®ã® Sanitizer æ§æã§å®è¡ããã¾ãã
ãã®æ§æã§ã¯ãXSS ã«å®å
¨ã¨è¦ãªããããã¹ã¦ã®è¦ç´ ã¨å±æ§ã許å¯ãããå®å
¨ã§ãªãã¨è¦ãªãããã¨ã³ãã£ãã£ã¯è¨±å¯ããã¾ããã
ç¬èªã®ãµãã¿ã¤ã¶ã¼ã¾ãã¯ãµãã¿ã¤ã¶ã¼è¨å®ãæå®ãããã¨ã§ã許å¯ã¾ãã¯é¤å»ãããè¦ç´ ã屿§ãã³ã¡ã³ãã鏿ã§ãã¾ãã
ãªãããµãã¿ã¤ã¶ã¼è¨å®ã§å®å
¨ã§ãªããªãã·ã§ã³ã許å¯ããã¦ããå ´åã§ãããã®ã¡ã½ããã使ç¨ããã¨ï¼æé»çã« Sanitizer.removeUnsafe() ãå¼ã³åºãããããï¼ããããã¯é¤å»ããã¾ãã
ä¿¡é ¼ã§ããªã HTML æååãè¦ç´ ã«æ¿å
¥ããéã¯ãElement.innerHTML ã®ä»£ããã« setHTML() ã使ç¨ãã¾ãããã
ã¾ããå®å
¨ã§ãªãè¦ç´ ã屿§ã仿§ä¸ã§ããå¿
è¦ãããå ´åãé¤ããElement.setHTMLUnsafe() ã®ä»£ããã«ä½¿ç¨ãã¾ãããã
ãªãããã®ã¡ã½ããã¯å ¥åæååã常㫠XSS æ»æã«èå¼±ãªã¨ã³ãã£ãã£ãããµãã¿ã¤ãºãããããä¿¡é ¼å API ã«ããã»ãã¥ãªãã£ä¿è·ãæ¤è¨¼ã¯è¡ããã¾ããã
ä¾
>åºæ¬çãªä½¿ãæ¹
ãã®ä¾ã¯ãsetHTML() ã使ç¨ã㦠HTML æååããµãã¿ã¤ãºããæ¿å
¥ããããã¤ãã®æ¹æ³ã示ãã¾ãã
// HTML ã®ãµãã¿ã¤ãºããã¦ããªãæååãå®ç¾©
const unsanitizedString = "abc <script>alert(1)<" + "/script> def";
// ID ã "target" ã®å¯¾è±¡è¦ç´ ãåå¾
const target = document.getElementById("target");
// setHTML() ãæ¢å®ã®ãµãã¿ã¤ã¶ã¼ã§å®è¡
target.setHTML(unsanitizedString);
// ç¬èªã®ãµãã¿ã¤ã¶ã¼ãå®ç¾©ãã setHTML() ã§ä½¿ç¨
// ããã¯è¦ç´ ã®ã¿ã許å¯ãã¾ãã div, p, button ï¼script ã¯å®å
¨ã§ã¯ãªãã®ã§åé¤ãããï¼
const sanitizer1 = new Sanitizer({
elements: ["div", "p", "button", "script"],
});
target.setHTML(unsanitizedString, { sanitizer: sanitizer1 });
// ç¬èªã® SanitizerConfig ã setHTML() å
ã§å®ç¾©
// ããã«ãããdivãpãbuttonãscriptãããã³ãã®ä»ã®å®å
¨ã§ãªãè¦ç´ /屿§ãé¤å»ããã
target.setHTML(unsanitizedString, {
sanitizer: { removeElements: ["div", "p", "button", "script"] },
});
setHTML() ã©ã¤ããµã³ãã«
ãã®ä¾ã§ã¯ãç°ãªããµãã¿ã¤ã¶ã¼ã§å¼ã³åºãããéã®ã¡ã½ããã®ãã©ã¤ãããã¢ãæä¾ãã¾ãã ã³ã¼ãã§ã¯ãæ¢å®ã®ãµãã¿ã¤ã¶ã¼ã¨ç¬èªã®ãµãã¿ã¤ã¶ã¼ã使ç¨ãã¦ããããã HTML æååããµãã¿ã¤ãºããã³æ¿å ¥ããããã®ãã¿ã³ãå®ç¾©ãã¦ãã¾ãã å ã®æååã¨ãµãã¿ã¤ãºããã HTML ã¯ãã°ã«è¨é²ããããããããããã®çµæã確èªã§ãã¾ãã
HTML
ãã® HTML ã§ã¯ãç°ãªããµãã¿ã¤ã¶ã¼ãé©ç¨ããããã® 2 ã¤ã® <button> è¦ç´ ãä¾ããªã»ããããããã®å¥ã®ãã¿ã³ãããã³æååãæ¿å
¥ããããã® <div> è¦ç´ ãå®ç¾©ãã¦ãã¾ãã
<button id="buttonDefault" type="button">æ¢å®</button>
<button id="buttonAllowScript" type="button">allowScript</button>
<button id="reload" type="button">åèªã¿è¾¼ã¿</button>
<div id="target">ã¿ã¼ã²ããè¦ç´ ã®å
ã®ã³ã³ãã³ã</div>
JavaScript
ã¾ãããã¹ã¦ã®ã±ã¼ã¹ã§å
±éã¨ãªãããµãã¿ã¤ãºå¯¾è±¡ã®æååãå®ç¾©ãã¾ãã
ããã«ã¯ <script> è¦ç´ 㨠onclick ãã³ãã©ã¼ãå«ã¾ãã¦ããããããã XSS ã«å¯¾ãã¦å®å
¨ã§ãªãã¨ããã¦ãã¾ãã
åæã«ãåèªã¿è¾¼ã¿ãã¿ã³ã®ãã³ãã©ã¼ãå®ç¾©ãã¾ãã
// HTML ã®å®å
¨ã§ãªãæååãå®ç¾©
const unsanitizedString = `
<div>
<p>This is a paragraph. <button onclick="alert('You clicked the button!')">Click me</button></p>
<script src="path/to/a/module.js" type="module"><script>
</div>
`;
const reload = document.querySelector("#reload");
reload.addEventListener("click", () => document.location.reload());
次ã«ãæ¢å®ã®ãµãã¿ã¤ã¶ã¼ã§ HTML ãè¨å®ãããã¿ã³ã®ã¯ãªãã¯ãã³ãã©ã¼ãå®ç¾©ãã¾ãã
ããã«ãããHTML æååãæ¿å
¥ããåã«ããã¹ã¦çå®å
¨ã§ãªãã¨ã³ãã£ãã£ãé¤å»ããã¾ãã
Sanitizer() ã³ã³ã¹ãã©ã¯ã¿ã¼ã®ä¾ã§ãã©ã®è¦ç´ ãé¤å»ãããããæ£ç¢ºã«ç¢ºèªã§ãã¾ãã
const defaultSanitizerButton = document.querySelector("#buttonDefault");
defaultSanitizerButton.addEventListener("click", () => {
// è¦ç´ ã®ã³ã³ãã³ããæ¢å®ã®ãµãã¿ã¤ã¶ã¼ã使ç¨ãã¦è¨å®
target.setHTML(unsanitizedString);
// ãµãã¿ã¤ãºåã¨æ¿å
¥å¾ã® HTML ããã°åºåãã
logElement.textContent =
"Default sanitizer: remove script element and onclick attribute\n\n";
log(`\nunsanitized: ${unsanitizedString}`);
log(`\nsanitized: ${target.innerHTML}`);
});
次ã®ã¯ãªãã¯ãã³ãã©ã¼ã¯ãç¬èªã®ãµãã¿ã¤ã¶ã¼ã使ã£ã¦ã¿ã¼ã²ãã HTML ãè¨å®ãã¾ãããã®ãµãã¿ã¤ã¶ã¼ã¯ã<div>ã<p>ã<script> è¦ç´ ã®ã¿ã許å¯ãããããã«è¨å®ãã¾ãã
setHTML ã¡ã½ããã使ç¨ãã¦ããããã <script> ãåæã«é¤å»ããããã¨ã«æ³¨æãã¦ãã ããã
const allowScriptButton = document.querySelector("#buttonAllowScript");
allowScriptButton.addEventListener("click", () => {
// ç¬èªã®ãµãã¿ã¤ã¶ã¼ã使ç¨ãã¦è¦ç´ ã®ã³ã³ãã³ããè¨å®
const sanitizer1 = new Sanitizer({
elements: ["div", "p", "script"],
});
target.setHTML(unsanitizedString, { sanitizer: sanitizer1 });
// ãµãã¿ã¤ãºåã¨æ¿å
¥å¾ã® HTML ããã°åºå
logElement.textContent =
"Sanitizer: {elements: ['div', 'p', 'script']}\n Script removed even though allowed\n";
log(`\nunsanitized: ${unsanitizedString}`);
log(`\nsanitized: ${target.innerHTML}`);
});
çµæ
ãæ¢å®ãã¨ãallowScriptããã¿ã³ãã¯ãªãã¯ããã¨ãããããæ¢å®ã®ãµãã¿ã¤ã¶ã¼ã¨ç¬èªã®ãµãã¿ã¤ã¶ã¼ã®å¹æã確èªã§ãã¾ãã
ãããã®å ´åãããµãã¿ã¤ã¶ã¼ã§æç¤ºçã«è¨±å¯ããå ´åã§ãã<script> è¦ç´ 㨠onclick ãã³ãã©ã¼ã¯é¤å»ããããã¨ã«æ³¨æãã¦ãã ããã
仿§æ¸
| 仿§æ¸ |
|---|
| HTML > # dom-element-sethtml > |