react-html-parser标签白名单配置:仅渲染用户提及链接其余转纯文本
实现方案
核心逻辑:通过配置react-html-parser的标签白名单规则,仅允许渲染你手动生成的合法用户主页<a>标签,其余所有用户输入的HTML内容全部转义为纯文本展示,避免开放全量HTML解析权限带来的安全风险。
1. 优化@提及替换逻辑(TS适配+安全转义)
不要直接删除用户输入的HTML标签,改为转义特殊字符,避免用户输入的<>类正常内容被误删,同时从根源上避免用户输入的原生HTML被解析:
const createLink = (comment: string): string => { // 第一步:转义所有HTML特殊字符,用户输入的标签会被转为纯文本展示 const escapedText = comment.replace(/[&<>"']/g, (char) => { const entityMap: Record<string, string> = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', }; return entityMap[char]; }); // 第二步:仅替换约定的@提及格式为a标签,增加用户ID格式校验避免恶意构造 // 正则根据你的用户ID规则调整,示例为仅允许字母、数字、下划线 return escapedText.replace(/@\[([^[\]]+)\]\((\w+)\)/g, (_, nickname, userId) => { // 可选:增加校验逻辑,判断userId是否在当前评论的提及用户列表中,避免伪造链接 return `<a href="/user/${encodeURIComponent(userId)}" rel="noopener noreferrer">@${nickname}</a>`; }); };
2. 配置react-html-parser仅解析合法a标签
利用react-html-parser提供的transform钩子自定义解析规则,只放行符合规则的用户链接,其余内容全部作为纯文本渲染:
import parse from 'react-html-parser'; import { convertNodeToElement } from 'react-html-parser'; const htmlParseOptions = { transform: (node: any, index: number) => { // 只放行格式为用户主页的a标签 if (node.type === 'tag' && node.name === 'a') { const href = node.attribs?.href; // 校验href必须是你约定的用户主页路径前缀 if (href?.startsWith('/user/')) { return convertNodeToElement(node, index, htmlParseOptions.transform); } } // 其余所有节点全部返回纯文本内容,不解析为HTML if (node.type === 'text') return node.data; return node.children?.map((child: any) => child.data).join('') || ''; }, }; // 调用解析 {parse(createLink(commentText), htmlParseOptions)}
额外安全优化
- 存储评论时可以提前提取所有@提及的用户ID存入评论关联字段,替换时校验匹配到的ID是否在该字段中,完全避免用户手动构造恶意链接
- 若用户ID存在特殊字符,统一用
encodeURIComponent处理后再拼接进href,避免路径注入风险
内容的提问来源于stack exchange,提问作者kiker
相关产品推荐
相关产品推荐

