本文目录导读:

过滤网页恶意代码(如XSS跨站脚本、SQL注入、恶意脚本等)是Web安全的核心,你需要从防御端(服务端/浏览器)和检测端(安全工具)两个维度入手。
以下是一套系统性的过滤方案,按策略优先级排序:
第一阶段:核心防御(必须做)
这是最有效的防线,避免恶意代码“进入”系统。
输入验证与过滤(服务端)
原则:所有用户输入都是不可信的。
- 白名单策略(推荐): 只允许特定格式。
用户名:只允许字母、数字、、(如/^[a-zA-Z0-9_-]{4,16}$/)。年龄:只允许数字(1-120)。邮箱:严格按RFC正则校验。
- 黑名单策略(不推荐): 过滤关键字如
<script>、alert、onerror、javascript:。缺点: 很容易被绕过(编码、大小写、事件触发组合等)。 - 编码与过滤库(必须使用): 不要自己写正则,使用成熟的库。
- Java:
OWASP Java Encoder、ESAPI。 - Python:
bleach(用于清理HTML)、markupsafe(用于转义)。 - PHP:
htmlspecialchars()、strip_tags()(谨慎使用)。 - Node.js:
DOMPurify、helmet(中间件)。
- Java:
输出转义(渲染端)
原则:在将数据显示到浏览器或数据库中时,清理掉可执行代码。
- HTML实体编码: 将
<换成<,>换成>, 换成", 换成',&换成&。- 场景: 用户发表的评论、用户名、文章标题。
- JavaScript 上下文转义: 如果数据插入到
<script>标签内或事件属性(如onclick="..."),需要进行JS字符串转义(反斜杠转义)。 - URL 编码: 如果数据拼接到 URL 参数或
href属性中,使用encodeURIComponent()。
CSP(内容安全策略)—— 浏览器端最强防线
原理: 通过 HTTP 响应头告诉浏览器“哪些来源的内容是安全的”,直接阻止内联脚本执行。
- 配置示例(响应头):
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-cdn.com; object-src 'none'; style-src 'self' 'unsafe-inline';
script-src 'self':只允许同源脚本。'unsafe-inline':如果不允许内联脚本,则<script>alert(1)</script>会直接被浏览器阻止。report-uri /csp-report:将违规行为报告给服务器。
- 效果: 就算攻击者成功注入了
<script>标签,浏览器也不会执行它。
HTTP Only + Secure Cookie
原理: 防止恶意代码通过 document.cookie 窃取会话。
HttpOnly:禁止浏览器 JS 访问 cookie(只能通过 HTTP 请求自动携带)。Secure:仅允许 HTTPS 传输 cookie。
第二阶段:特定场景防御
富文本编辑器(如 TinyMCE、Quill)
场景: 用户需要插入图片、链接、加粗等(需要部分CSS/HTML)。 策略: 绝对不能直接信任编辑器返回的HTML。
- 服务器端过滤: 使用
DOMPurify(Node.js/Python/Java 版本可用)对返回的 HTML 进行清理。- 允许的标签:
<b>,<i>,<u>,<a>,<img>。 - 允许的属性:
href,src,alt(绝不允许onerror,onload,onclick,style)。 - 过滤
javascript:伪协议:<a href="javascript:alert(1)">会被移除。
- 允许的标签:
SQL 注入防御
原则: 永远不要拼SQL字符串。
- 使用参数化查询(Prepared Statement): 这是唯一有效的方式。
# 错误:cursor.execute("SELECT * FROM users WHERE name='" + username + "'") # 正确: cursor.execute("SELECT * FROM users WHERE name=?", (username,)) - ORM 框架: SQLAlchemy(Python)、Hibernate(Java)、Eloquent(PHP)等默认使用了参数化查询。
文件上传防御
场景: 用户上传头像或附件。 策略:
- 白名单扩展名:
.jpg,.png,.gif(不允许.exe,.php,.html)。 - MIME类型检查: 不信任
Content-Type,要检查文件真实魔数(Magic Number/Magic bytes)。 - 保存时重命名: 不要使用用户提供的文件名(防止 路径穿越),生成唯一文件名。
- 存储到对象存储: 存放于非 Web 目录(如只读存储桶),通过 CDN 或签名 URL 访问。
第三阶段:检测与监控(主动防御)
WAF(Web应用防火墙)
- 商用: Cloudflare WAF、AWS WAF、阿里云WAF。
- 开源: ModSecurity(可配合 Nginx/Apache)。
- 作用: 在流量进入应用前,通过规则库匹配并拦截恶意Payload(如
UNION SELECT、<img src=x onerror=...>)。
安全头与扫描
- X-Content-Type-Options: nosniff:禁止浏览器嗅探响应内容类型。
- X-Frame-Options: SAMEORIGIN:防止点击劫持(Clickjacking)。
- 定期扫描: 使用 OWASP ZAP 或 Burp Suite 对站点进行自动化扫描。
第四阶段:具体代码示例(Java + Python)
示例1:Java 过滤 XSS(使用 OWASP 库)
import org.owasp.encoder.Encode;
String userInput = "<script>alert('xss')</script>";
// 输出到HTML body时使用:
String safeOutput = Encode.forHtml(userInput);
// 输出结果: <script>alert('xss')</script>
// 输出到URL参数时使用:
String safeUrlParam = Encode.forUriComponent(userInput);
示例2:Python Flask + bleach 过滤富文本
import bleach
from flask import request, jsonify
def sanitize_article(request):
raw_html = request.form['content']
# 只允许特定标签和属性
allowed_tags = ['p', 'b', 'i', 'u', 'a', 'img']
allowed_attrs = {
'a': ['href', 'title', 'rel'],
'img': ['src', 'alt', 'width', 'height']
}
# 清理:移除onclick、javascript:等
clean_html = bleach.clean(raw_html, tags=allowed_tags, attributes=allowed_attrs, strip=True)
return clean_html
过滤的黄金法则
- 先校验后存储: 在入库前,做好输入验证(白名单优先)。
- 在输出时转义: 无论数据是否被存储,显示给用户前进行上下文转义(HTML/JS/URL)。
- 开启 CSP 头: 这是少数可以完全阻止0day XSS的工具。
- 永远不用黑名单: 攻击者总能想出绕过方法(
<scr\0ipt>、\u003c、<等)。
最危险的误区: 在前端(JS)过滤,后端不检查,前端过滤只为了用户体验,后端必须重新检查,因为攻击者可以直接构造 HTTP 请求。