本文目录导读:

过滤特殊字符通常是为了防止注入攻击(如SQL注入、XSS攻击)、数据清洗或格式校验。
过滤拦截的方式取决于使用场景(前端/后端、技术栈)以及“特殊字符”的具体定义,以下是几种主流且有效的处理方案:
核心原则
- 后端必须做:前端过滤仅用于用户体验,后端是安全底线。
- 不要只依赖黑名单:黑名单容易被绕过,优先采用白名单(只允许特定字符)或转义(Escaping)。
- 视语境而定:不同的上下文(HTML、SQL、URL、JSON)对特殊字符的定义不同。
后端过滤拦截(核心)
通用防注入:使用参数化查询(Prepared Statements)
这是防止SQL注入最有效的方法,它从根本上避免了拼接SQL语句。
-
错误做法:
# Python (易受攻击) cursor.execute("SELECT * FROM users WHERE name = '" + user_input + "'") -
正确做法:
# Python (参数化查询) cursor.execute("SELECT * FROM users WHERE name = %s", (user_input,))
输出转义(针对XSS攻击)
在将数据输出到HTML页面时,进行转义,而不是直接输出。
- Java (JSP/Servlet):使用
StringEscapeUtils.escapeHtml4(input) - Python (Flask/Django):模板引擎默认自动转义(如
{{ variable }}) - JavaScript (Node.js):使用
html-entities库 - 示例:将
<script>alert('x')</script>转义为<script>alert('x')</script>
使用库函数过滤(白名单与黑名单结合)
在Java/Spring中,可以使用成熟的过滤库:
- OWASP Java HTML Sanitizer:只允许安全的HTML标签。
- AntiSamy:定义策略文件(policy.xml)来限制允许的字符和标签。
示例(Java + 自定义过滤器拦截请求):
// 自定义过滤器,拦截所有请求,清理特殊字符
public class XSSFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
// 1. 获取请求参数
// 2. 遍历参数,替换或删除 < > " ' ( ) & # 等字符
String cleanValue = originalValue.replaceAll("<", "<").replaceAll(">", ">");
// 或者直接删除: originalValue.replaceAll("[<>\"'()]", "");
// 3. 将清洗后的参数放回Request (通过自定义RequestWrapper)
chain.doFilter(wrappedRequest, res);
}
}
白名单示例(推荐):
// Node.js / JavaScript (仅允许字母、数字、中文、下划线)
function filterInput(str) {
return str.replace(/[^a-zA-Z0-9\u4e00-\u9fa5_]/g, '');
}
前端过滤拦截(用户体验层)
前端拦截不能替代后端拦截,主要用于提升用户反馈速度。
输入框监听(实时拦截)
通过 JavaScript 阻止非法字符输入。
<input type="text" id="username" />
<script>
document.getElementById('username').addEventListener('keydown', function(e) {
// 只允许输入字母、数字、下划线
var allowed = /[a-zA-Z0-9_]/;
var key = String.fromCharCode(e.keyCode);
if (!allowed.test(key) && e.keyCode !== 8 && e.keyCode !== 46) { // 允许退格和删除
e.preventDefault();
}
});
</script>
表单提交时校验(拦截提交)
在提交前拦截,并给出提示。
function validateForm() {
var input = document.getElementById('comment').value;
// 检测是否包含非法字符 (HTML标签)
if (/[<>"'&]/.test(input)) {
alert('输入内容包含非法特殊字符,请修改!');
return false;
}
return true;
}
使用输入框的 pattern 属性(HTML5)
最简单的拦截方式,无需 JS,但不支持所有浏览器。
<input type="text" pattern="[a-zA-Z0-9]+" title="仅允许英文和数字" required>
服务端中间件/网关层过滤
如果系统有多种后端语言,可以在统一的网关(Nginx、API Gateway、WAF)上拦截。
Nginx + Lua/ModSecurity
通过 Nginx 的 ngx_lua 模块或 ModSecurity 模块,在请求到达后端之前,直接拦截。
# Nginx 简单过滤 (仅示例,不推荐用于生产)
if ($query_string ~* "(\<|>|'|\"|%27|%3C|%3E)") {
return 403;
}
Web应用防火墙(WAF)
商业WAF(如Cloudflare、AWS WAF、阿里云WAF)可以智能识别和拦截SQL注入、XSS等攻击流量,这是最省心的方式。
特定场景的过滤方案
| 场景 | 特殊字符 | 推荐过滤方式 |
|---|---|---|
| SQL命令 | exec |
参数化查询(首选),绝不动态拼接。 |
| HTML/XML | < > & |
HTML实体转义:< > " ' & |
| Javascript | < > eval |
JSON.stringify() 或 Base64编码输出。 |
| URL参数 | & 空格 |
URL编码:encodeURIComponent(value) |
| 文件路径 | \0 |
白名单路径 + basename() 函数。 |
| 命令行 | & \n > |
禁止直接拼接系统命令,使用API或沙箱。 |
总结建议
- 层级防御:前端(防误触) + 后端(核心防线,使用参数化查询 + 输出转义) + 网关/WAF(边界防御)。
- 不要试图“清理” SQL语句:使用预编译是终点。
- 特殊字符定义要清晰:是只过滤HTML标签?还是只防SQL注入?还是在比如用户名等场景下只需要字母数字?明确需求后,选择对应的过滤策略。