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

改用createElement替代模板字面量能否防范信使应用XSS风险?

解决信使应用的XSS问题:改用createElement可行吗?

你的信使应用当前通过模板字面量结合insertAdjacentHTML渲染对话,导致last_message.text中的恶意HTML/脚本被解析执行,引发XSS风险。应用仅支持纯文本消息,需要彻底阻断富内容渲染。

示例恶意消息

var app = document.querySelector('body'); app.innerHTML = '<img src="x" onerror="alert(1)">';

当前存在风险的渲染代码

renderDialogs: () => {
  const dialogList = document.getElementById('dialogsList');
  dialogList.textContent = '';

  const df = document.createDocumentFragment();

  dialogs.list.forEach(
    ({
      id,
      created,
      modified,
      username,
      other_user_id,
      unread_count,
      last_message,
    }) => {
      const btn = document.createElement('button');
      btn.classList =
        'list-group-item list-group-item-action list-group-item';
      btn.dataset.username = username;
      btn.dataset.userId = other_user_id;

      const btnContent = `
      <div class="d-flex flex-column gap-1 disable-pointer-events">
        <h5 class="mb-0 fs-6">${username}</h5>
        <p class="mb-0 text-muted preview-text">${last_message.text}</p>
        <p class="mb-0 dialog-unread"><span class="dialog-unread-count">${unread_count}</span> unread messages</p>
      </div>
    `;

      btn.insertAdjacentHTML('beforeend', btnContent);
      df.appendChild(btn);
    },
  );
  dialogList.appendChild(df);
},

回答

改用createElement配合textContent设置文本内容,完全可以解决这个XSS问题。

原因很直接:insertAdjacentHTML会把传入的字符串当作HTML解析,模板字面量插入的恶意内容会被浏览器执行;而createElement创建元素后,通过textContent赋值时,所有内容都会被当作纯文本处理,浏览器不会解析任何HTML标签,自然也不会执行脚本。

以下是修改后的安全渲染代码:

renderDialogs: () => {
  const dialogList = document.getElementById('dialogsList');
  dialogList.textContent = '';

  const df = document.createDocumentFragment();

  dialogs.list.forEach(
    ({
      username,
      other_user_id,
      unread_count,
      last_message,
    }) => {
      const btn = document.createElement('button');
      btn.className = 'list-group-item list-group-item-action list-group-item';
      btn.dataset.username = username;
      btn.dataset.userId = other_user_id;

      // 创建容器div
      const container = document.createElement('div');
      container.className = 'd-flex flex-column gap-1 disable-pointer-events';

      // 创建用户名标题
      const usernameEl = document.createElement('h5');
      usernameEl.className = 'mb-0 fs-6';
      usernameEl.textContent = username;
      container.appendChild(usernameEl);

      // 创建消息预览文本
      const previewTextEl = document.createElement('p');
      previewTextEl.className = 'mb-0 text-muted preview-text';
      previewTextEl.textContent = last_message.text;
      container.appendChild(previewTextEl);

      // 创建未读消息提示
      const unreadEl = document.createElement('p');
      unreadEl.className = 'mb-0 dialog-unread';
      
      const unreadCountSpan = document.createElement('span');
      unreadCountSpan.className = 'dialog-unread-count';
      unreadCountSpan.textContent = unread_count;
      unreadEl.appendChild(unreadCountSpan);
      unreadEl.append(' unread messages'); // 追加纯文本
      
      container.appendChild(unreadEl);

      btn.appendChild(container);
      df.appendChild(btn);
    },
  );
  dialogList.appendChild(df);
},

这种方式从根源上避免了HTML解析,确保所有用户输入内容都以纯文本形式展示,彻底阻断XSS攻击路径。

内容的提问来源于stack exchange,提问作者Sora

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 18:53:33