本文目录导读:

输入过滤是防御XSS(跨站脚本攻击)的重要环节,但仅靠输入过滤是不够的,需要与输出编码结合,以下是针对XSS的输入过滤策略及实现方法:
核心原则:过滤+编码双保险
- 输入过滤:拦截明显恶意字符(如
<script>、onerror等)。 - 输出编码:对输出到HTML、JavaScript、CSS等不同上下文的数据进行编码(更关键)。
输入过滤的主要方法
(1) 黑名单过滤(不推荐)
- 原理:拦截已知的恶意关键字或模式。
- 示例(PHP简单实现):
$input = str_replace(['<script>', 'onerror=', 'javascript:'], '', $_POST['input']);
- 缺陷:攻击者可绕过(如
<ScRiPt>、<img src=x onerror=alert(1)>等变体)。
(2) 白名单过滤(推荐)
- 原理:只允许特定类型的数据(如字母、数字、安全符号)。
- 示例(仅允许数字和逗号):
import re input_data = re.sub(r'[^0-9,]', '', user_input)
- 适用场景:严格格式的输入(如年龄、邮编、选择框值)。
(3) 输入验证(语义层过滤)
- 原理:按业务逻辑验证数据格式(如邮箱、URL)。
- 示例(验证邮箱格式):
import re if not re.match(r'^[\w\.-]+@[\w\.-]+\.\w+$', user_input): return "Invalid email"
(4) HTML标签剥离(保留安全标签)
- 使用安全库(如HTMLPurifier、Bleach)白名单保留标签。
- 示例(Python
bleach库):import bleach allowed_tags = ['b', 'i', 'a', 'p'] allowed_attrs = {'a': ['href', 'title']} clean_html = bleach.clean(user_input, tags=allowed_tags, attributes=allowed_attrs)
关键过滤规则(针对常见XSS向量)
| 拦截目标 | 过滤模式(正则或替换) | 说明 |
|---|---|---|
<script>及变体 |
/<[^>]*script/gi |
但可能误伤正常<script>标签(应使用白名单) |
on事件处理器 |
/(\s|"|'|>)on\w+\s*=/gi |
如onclick、onerror、onload |
javascript:伪协议 |
/javascript:/gi |
URL中的<a href="javascript:alert(1)"> |
data:协议 |
/data:/gi |
<img src="data:image/svg+xml;..."> |
| 十六进制/Unicode编码绕过 | /(\\x[0-9a-f]{2})/gi |
如<a href="\x6aavascript:..."> |
| 特殊HTML实体(双重编码) | 过滤<、>等(但应输出编码) |
不是输入过滤强项 |
过滤的局限性(为什么不能只靠过滤)
| XSS绕过方式 | 示例 | 过滤失效原因 |
|---|---|---|
| 大小写变体 | <ScRiPt> vs <script> |
黑名单需处理多种大小写组合 |
| 嵌套或拆分 | <scr<script>ipt> |
过滤后剩余<script> |
| URL编码 | %3Cscript%3E(即<script>) |
输入解码前未检查 |
| 使用转义序列 | \x3cscript\x3e |
过滤模式未匹配 |
| 利用CSS表达式(旧IE) | <style>中expression(...) |
纯HTML过滤无法拦截 |
| SVG/XML命名空间 | <svg><script>alert(1)</script> |
需额外处理非HTML上下文 |
实践建议
-
分层防御:
- 输入层:严格白名单过滤(如数字、枚举值)+ 格式验证。
- 存储层:对特殊字符进行转义(可选,如
<→<)。 - 输出层:必须根据上下文编码(HTML实体、JS字符串、CSS、URL)。
-
使用成熟库:
- Java:
OWASP Java Encoder、JSOUP(剥HTML)。 - Python:
bleach、MarkupSafe。 - PHP:
HTMLPurifier、strip_tags()(谨慎使用)。 - JavaScript:
DOMPurify(前端清理)。
- Java:
-
测试绕过:
- 使用工具如OWASP ZAP、Burp Suite生成XSS payload列表。
- 手动测试:
<img src=x onerror=alert(1)>、<svg/onload=alert(1)>。
过滤永远不是唯一防线
- 输入过滤:适合严格格式(数字、选项),或作为“缩减攻击面”的手段。
- 输出编码:才是防御XSS的核心(对HTML实体、JS字符串、CSS、URL分别编码)。
- 黄金法则:永不信任用户输入,对不同输出上下文分别编码。