上周帮朋友看一个社区网站,后台日志里每天冒出几百条带可疑链接的评论——有的伪装成‘优惠券领取’,有的夹带base64编码的js脚本。这不是个例,而是内容安全防护没跟上业务节奏的典型信号。
别只盯着防火墙,内容本身才是突破口
很多团队一说安全,第一反应是买WAF、配ACL、加固服务器。但攻击者早就不硬闯了,他们更爱钻内容入口的空子:用户发的帖子、上传的图片名、表单里的昵称字段、甚至API返回的JSON字段值……这些地方一旦缺校验,就可能变成XSS、SQL注入或恶意重定向的温床。
四个落地动作,比堆工具更管用
1. 输入即过滤,不是等入库再清洗
比如用户提交昵称,后端接收到的第一时间就做基础剥离:
function sanitizeInput(str) {
return str
.replace(/<script[^>]*>.*?<\/script>/gi, '')
.replace(/javascript:/gi, '')
.replace(/on\w+\s*=\s*"[^"]*"/gi, '')
.trim();
}别指望前端JS能拦住所有请求,绕过太容易。服务端必须有独立、轻量、可复用的净化逻辑。2. 文件上传加三道锁
不只是限制后缀名(.jpg/.png),还要:
• 检查文件头魔数(比如PNG开头必须是89 50 4E 47);
• 重命名存储(UUID + 时间戳,彻底丢弃原始文件名);
• 单独部署静态资源域,禁止执行权限(Nginx配置里加上 location ~ \.php$ { deny all; })。
3. 敏感词不靠关键词列表硬匹配
“支那”“法轮”这类词容易被拆字、谐音、符号隔开。建议引入轻量级NLP分词+语义模糊匹配,比如用Jieba分词后,对每个词元计算编辑距离,阈值设为2。同时把运营反馈高频绕过词实时加入规则池,形成闭环。
4. API响应也要“防泄漏”
一个用户调用 /api/user/profile?id=123,返回体里如果包含 {"email": "admin@xxx.com", "phone": "138****1234"},就等于把内部联系人信息白送出去。默认只返回当前用户有权查看的字段,敏感字段统一脱敏处理(手机号中间四位用*代替,邮箱@前保留首字母)。
真实场景:评论区是怎么被攻破又救回来的
某本地生活平台上线新活动,开放用户晒单评论并带图。三天后,大量评论末尾自动追加一行:
<a href="https://malicious-site.net/track?id=xxx" target="_blank">点击查看中奖详情</a>排查发现,富文本编辑器允许标签,但后端未对href属性做协议白名单(仅允许http/https),也未校验域名是否在备案列表内。修复方案很简单:渲染前统一替换所有非白名单href为#,并加data-original-url存原始值,点击时由前端SDK做二次鉴权。内容安全不是一次性工程,它藏在每次表单提交、每次文件上传、每次API返回的细节里。做得扎实,用户看不见;漏掉一处,可能就是整个账号体系的缺口。