从安全漏洞角度寻求JavaScript中innerHTML的替代方案
替代innerHTML的安全方案
从安全角度看,innerHTML的核心风险是会解析并执行传入的HTML内容,若change_obj中的数据包含用户可控的恶意代码,极易引发XSS攻击。以下是几种更安全且比手动逐个创建元素更简洁的替代方案:
原问题代码示例
存在风险的innerHTML实现
td.innerHTML = "<b>"+change_obj["old_end_cust_id"]+"</b>," + "<br>" + change_obj["old_address"].join(",<br>")
可行但繁琐的原生DOM创建方案
var parentDivTag11 = document.createElement("div"); var parentBoldTag11 = document.createElement("b"); parentBoldTag11.textContent = change_obj["old_end_cust_id"]+","; parentDivTag11.appendChild(parentBoldTag11); for (let i = 0; i < change_obj["old_address"]?.length; i++) { var divTag11 = document.createElement("div"); divTag11.textContent=change_obj["old_address"][i]+","; parentDivTag11.append(divTag11); } td.appendChild(parentDivTag11);
更简洁的安全替代方案
方案1:文本转义+insertAdjacentHTML
先将用户输入内容转义为HTML实体,再拼接可信的HTML结构,最后用insertAdjacentHTML插入(仅确保HTML结构可信时使用,用户内容必须先转义):
// 简单HTML转义函数 function escapeHtml(text) { return text.replace(/[&<>"']/g, char => { const entities = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; return entities[char]; }); } const escapedId = escapeHtml(change_obj["old_end_cust_id"]); const escapedAddresses = change_obj["old_address"].map(addr => escapeHtml(addr)).join("<br>"); td.insertAdjacentHTML('beforeend', `<b>${escapedId},</b><br>${escapedAddresses}`);
方案2:DocumentFragment简化DOM创建
通过文档片段一次性插入所有元素,减少DOM重绘,同时简化代码:
const fragment = document.createDocumentFragment(); // 创建加粗ID元素 const boldId = document.createElement("b"); boldId.textContent = `${change_obj["old_end_cust_id"]},`; fragment.appendChild(boldId); fragment.appendChild(document.createElement("br")); // 批量添加地址元素 change_obj["old_address"]?.forEach(addr => { const addrEl = document.createElement("span"); addrEl.textContent = `${addr},`; fragment.appendChild(addrEl); fragment.appendChild(document.createElement("br")); }); // 移除最后多余的<br> if (fragment.lastChild?.tagName === "BR") { fragment.removeChild(fragment.lastChild); } td.appendChild(fragment);
方案3:使用<template>元素
利用模板元素的内容克隆能力,兼顾结构可读性与文本安全性:
// 创建模板 const template = document.createElement("template"); template.innerHTML = `<b></b><br>`; // 克隆模板内容 const content = template.content.cloneNode(true); // 设置ID文本(textContent自动转义) content.querySelector("b").textContent = `${change_obj["old_end_cust_id"]},`; // 添加地址元素 change_obj["old_address"]?.forEach(addr => { const addrEl = document.createElement("span"); addrEl.textContent = `${addr},`; content.appendChild(addrEl); content.appendChild(document.createElement("br")); }); // 移除最后多余的<br> if (content.lastChild?.tagName === "BR") { content.removeChild(content.lastChild); } td.appendChild(content);
所有方案的核心逻辑都是将用户提供的内容作为纯文本处理,避免HTML解析带来的XSS风险,同时通过代码优化解决手动创建元素的繁琐问题。
内容的提问来源于stack exchange,提问作者ArunKarthick
相关产品推荐
相关产品推荐

