使用innerHTML渲染内容时如何仅保留b、u、i等指定标签与属性
实现方案
直接用原生DOMParser解析用户输入的HTML字符串,遍历DOM节点过滤白名单标签和属性,完全规避正则匹配HTML的边界缺陷,核心实现逻辑如下:
// 配置白名单 const ALLOWED_TAGS = ['B', 'I', 'U', 'DIV']; // 仅允许的属性,这里只保留style const ALLOWED_ATTRS = ['style']; function filterUserHtml(inputStr) { const parser = new DOMParser(); // 解析输入为DOM文档 const doc = parser.parseFromString(inputStr, 'text/html'); const fragment = document.createDocumentFragment(); // 递归处理节点 function processNode(node) { // 文本节点直接创建新的文本节点返回,自动转义特殊字符 if (node.nodeType === Node.TEXT_NODE) { return document.createTextNode(node.textContent); } // 元素节点判断是否在白名单 if (node.nodeType === Node.ELEMENT_NODE) { const tagName = node.tagName; // 不在白名单的标签,把内容转成文本返回 if (!ALLOWED_TAGS.includes(tagName)) { return document.createTextNode(node.outerHTML); } // 额外校验div必须有style属性 if (tagName === 'DIV' && !node.hasAttribute('style')) { return document.createTextNode(node.outerHTML); } // 创建合法元素 const el = document.createElement(tagName.toLowerCase()); // 只保留允许的属性 ALLOWED_ATTRS.forEach(attr => { if (node.hasAttribute(attr)) { el.setAttribute(attr, node.getAttribute(attr)); } }); // 递归处理子节点 Array.from(node.childNodes).forEach(child => { const processedChild = processNode(child); if (processedChild) el.appendChild(processedChild); }); return el; } // 其他类型节点(注释、script等)直接丢弃 return null; } // 处理body下所有根节点 Array.from(doc.body.childNodes).forEach(node => { const processed = processNode(node); if (processed) fragment.appendChild(processed); }); // 转成HTML字符串返回,或者直接把fragment插入DOM const tempDiv = document.createElement('div'); tempDiv.appendChild(fragment); return tempDiv.innerHTML; }
结合现有逻辑的用法
const fullBlogContainer = document.querySelector(".fullblog-container"); // 替换为你实际用于渲染内容的DOM节点 const renderContainer = document.querySelector(".render-container"); function submitBlocks() { const allChildren = Array.from(fullBlogContainer.children); const filterChildren = allChildren.filter((elem) => elem.tagName != "BUTTON"); const userInput = filterChildren[0].value; // 过滤后再用innerHTML渲染 const safeHtml = filterUserHtml(userInput); renderContainer.innerHTML = safeHtml; }
可选扩展
如果要进一步防范style属性内的恶意代码(比如javascript:、expression()等旧版CSS攻击写法),可以增加对style内容的正则校验,仅允许color、font-size等你需要的合法CSS属性即可。
内容的提问来源于stack exchange,提问作者RiBi
相关产品推荐
相关产品推荐

