You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.15 22:45:04