Skip to content

原生 DOM 的安全操作

HTML 标签操作,限定/过滤传入变量值

在使用下列几个 DOM API 时:

  • innerHTML
  • outerHTML
  • document.write()
  • document.writeln()

如变量值外部可控,应对特殊字符 &, <, >, ", ' 做编码转义,或使用安全的 DOM API 替代,比如:innerText

例如:假设 params 为用户输入, text 为 DOM 节点

const { user } = params;
// bad:将不可信内容带入 HTML 标签操作
text.innerHTML = `Follow @${user}`;

// good: innerHTML 操作前,对特殊字符编码转义
function htmlEncode(iStr) {
	let sStr = iStr;
	sStr = sStr.replace(/&/g, "&amp;");
	sStr = sStr.replace(/>/g, "&gt;");
	sStr = sStr.replace(/</g, "&lt;");
	sStr = sStr.replace(/"/g, "&quot;");
	sStr = sStr.replace(/'/g, "&#39;");
	return sStr;
}

let { user } = params;
user = htmlEncode(user);
text.innerHTML = `Follow @${user}`;

const { user } = params;
// good: 使用安全的DOM API替代innerHTML
text.innerText = `Follow @${user}`;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

HTML 属性操作,限定/过滤传入变量值

  1. 使用 element.setAttribute(name, value) 时,如第一个参数值 name 外部可控,应用白名单限定允许操作的属性范围。

  2. 使用 element.setAttribute(name, value) 时,操作:

    • a.href
    • ifame.src
    • form.action
    • embed.src
    • object.data
    • link.href
    • area.href
    • input.formaction
    • button.formaction

等属性时,如第二个参数值 value 外部可控,应参考 JavaScript 页面类规范 1.3.1 部分,限定页面重定向或引入资源的目标地址。

示例:

// good: setAttribute 操作前,限定引入资源的目标地址
function addExternalCss(e) {
	const t = document.createElement('link');
	t.setAttribute('href', e),
	t.setAttribute('rel', 'stylesheet'),
	t.setAttribute('type', 'text/css'),
	document.head.appendChild(t)
}

function validURL(sUrl) {
  return !!((/^(https?:\/\/)?[\w\-.]+\.(qq|tencent)\.com($|\/|\\)/i)
  .test(sUrl) || (/^[\w][\w/.\-_%]+$/i)
  .test(sUrl) || (/^[/\\][^/\\]/i).test(sUrl));
}

let sUrl = "https://evil.com/1.css"

if (validURL(sUrl)) {
	addExternalCss(sUrl);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
原生 DOM 的安全操作 has loaded