在当今的 Web 应用中,富文本内容无处不在——博客文章、商品详情、用户评论、论坛帖子,几乎每一个允许用户输入并展示格式化内容的场景,都离不开富文本。然而,富文本的灵活性也为攻击者提供了可乘之机。如何在保留格式表达能力的同时,确保存储与展示环节的安全性,是每一位开发者必须面对的问题。本文将从 XSS 防御、SQL 注入防护以及服务器安全加固三个层面,系统梳理富文本内容的安全处理方案。
一、XSS 的常见方式与前端防御
XSS(跨站脚本攻击)是富文本场景中最常见的安全威胁。攻击者通过注入恶意脚本,在用户浏览页面时执行,从而窃取 Cookie、会话令牌,甚至发起蠕虫式传播。
常见 XSS 注入方式
1. 存储型 XSS
攻击者将恶意脚本提交到服务器并持久化存储(如评论、个人简介),当其他用户访问该页面时,脚本自动执行。这是富文本场景中最危险的类型。
2. 反射型 XSS
恶意脚本作为请求参数发送给服务器,服务器未经过滤直接返回给浏览器执行。常见于搜索框、错误提示页面。
3. DOM 型 XSS
前端 JavaScript 直接从 location.hash、document.URL 等来源获取数据并插入 DOM,未做安全处理。例如:
document.getElementById('content').innerHTML = location.hash.slice(1);
攻击者构造 #<img src=x onerror=alert(1)> 即可触发。
4. 富文本中的隐蔽向量
富文本编辑器允许的标签和属性众多,攻击者常利用以下方式绕过过滤:
<img src=x onerror=alert(1)><a href="javascript:alert(1)">点击</a><svg onload=alert(1)><iframe src="data:text/html;base64,...">- 利用 HTML 实体编码、大小写混写、空字符截断等绕过黑名单
前端防御策略
1. 输出编码
根据输出位置选择正确的编码方式:HTML 内容区使用 HTML 实体编码,属性区使用属性编码,JavaScript 上下文使用 JS 编码。切勿直接将用户输入拼接到 DOM 中。
2. 使用成熟的净化库
推荐使用 DOMPurify 对富文本 HTML 进行白名单净化:
import DOMPurify from 'dompurify';
const clean = DOMPurify.sanitize(dirtyHTML, {
ALLOWED_TAGS: ['p', 'b', 'i', 'u', 'a', 'ul', 'ol', 'li', 'h1', 'h2', 'blockquote', 'code', 'pre'],
ALLOWED_ATTR: ['href', 'title', 'target']
});
3. 设置 CSP 响应头
内容安全策略(CSP)作为最后一道防线,可有效限制脚本执行来源:
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none';
4. 避免使用 innerHTML
优先使用 textContent 或 createElement 等安全 API。若必须使用 innerHTML,务必先经过净化处理。
需要特别强调的是,前端防御只是第一道关卡。攻击者完全可以绕过前端直接向服务器发送请求,因此服务端同样必须进行严格的过滤和净化。
二、MySQL 防止 SQL 注入的几种写法
SQL 注入与 XSS 常常相伴而生。当富文本内容被存入数据库或从数据库取出时,如果 SQL 语句拼接不当,攻击者就能通过构造恶意输入篡改查询逻辑,甚至拖库。
危险写法(务必避免)
$sql = "SELECT * FROM articles WHERE id = " . $_GET['id'];
$sql = "INSERT INTO comments (content) VALUES ('" . $content . "')";
任何直接将用户输入拼接到 SQL 语句中的做法都是不可接受的。
安全写法
1. 预处理语句(Prepared Statements)——首选方案
预处理语句将 SQL 结构与数据分离,数据库先编译语句模板,再绑定参数,从根本上杜绝注入:
$stmt = $pdo->prepare("SELECT * FROM articles WHERE id = :id");
$stmt->execute([':id' => $id]);
cursor.execute("INSERT INTO comments (content) VALUES (%s)", (content,))
2. 参数化查询配合类型约束
确保绑定参数时指定正确的类型,避免类型混淆带来的风险:
PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE age > ?");
ps.setInt(1, age);
3. 使用 ORM 框架
主流 ORM(如 Hibernate、SQLAlchemy、Eloquent)默认使用参数化查询,能有效降低注入风险。但需注意,ORM 中的原生 SQL 拼接方法(如 whereRaw)仍可能引入漏洞。
4. 最小权限原则
为数据库应用账户分配最小必要权限,禁止使用 root 或具有 DROP、FILE 权限的账户连接应用。即使发生注入,也能限制损害范围。
5. 输入验证与白名单
对于排序字段、表名等无法参数化的位置,使用严格白名单校验:
$allowed = ['title', 'created_at', 'views'];
$order = in_array($_GET['order'], $allowed) ? $_GET['order'] : 'created_at';
三、Linux 服务器安全加固清单
富文本内容最终存储在服务器上,服务器本身的安全是整个链路的基础。以下是关键的加固措施:
账户与权限
- 禁用 root 远程登录,使用普通用户 + sudo 提权
- 删除或锁定不必要的系统账户,设置强密码策略
- 配置 SSH 密钥登录,禁用密码认证,修改默认端口
- 遵循最小权限原则,Web 目录权限设置为 755,文件为 644
网络与防火墙
- 使用 iptables 或 firewalld 仅开放必要端口(80、443、SSH)
- 部署 Fail2ban 防止暴力破解
- 关闭不必要的服务与端口,定期使用
netstat审计
系统与软件更新
- 定期更新系统补丁:
apt update && apt upgrade或yum update - 订阅安全公告,及时修复 Web 服务器、数据库、运行时漏洞
- 移除不再使用的软件包,减少攻击面
日志与监控
- 启用并集中管理系统日志、Web 访问日志、数据库日志
- 配置日志轮转,防止磁盘写满
- 部署监控告警,对异常登录、异常进程、异常流量及时响应
数据安全
- 数据库定期备份,备份文件加密存储并异地保存
- 敏感数据加密存储,传输层启用 TLS
- 对上传的富文本附件进行类型校验和病毒扫描,存储于 Web 根目录之外
结语
富文本内容的安全处理是一个贯穿前端、后端、数据库和服务器的系统工程。前端通过净化与 CSP 阻断 XSS 执行,后端通过参数化查询杜绝 SQL 注入,服务器通过加固清单缩小攻击面。三者缺一不可,任何一层的疏忽都可能导致整个防线崩溃。安全没有银弹,唯有纵深防御、持续审计,才能在功能与安全之间找到平衡。
未经允许不得转载:任鹏个人博客 » 富文本内容存储与展示的安全处理方案


朋友圈点赞图在线生成源码