filter不能直接转义sql字符,因其仅拦截http请求响应而不处理sql;sql注入防护应在dao层用preparedstatement绑定参数,或mybatis中禁用${}、只用#{},辅以白名单校验;filter仅适合日志告警,不可修改请求体。

Filter里不能直接转义SQL字符
Filter本身不处理SQL语句,它只拦截HTTP请求和响应。所谓“对SQL字符转义”,本质是防止SQL注入,但这个动作必须发生在SQL拼接之前——通常在DAO层或ORM框架内部。把转义逻辑塞进Filter,不仅位置错、时机错,还会破坏请求体原始语义(比如JSON里的'或"被误删),反而引发解析失败。
为什么常见Filter方案会失效
很多网上示例用Filter遍历request.getParameterMap(),对每个值做String.replace("'", "\'")之类操作。问题在于:
- 只覆盖
GET参数,漏掉POST正文(尤其是application/json)、multipart/form-data、path variable - 转义规则硬编码,无法适配不同数据库(如PostgreSQL用
$$定界符,MySQL用反引号) - 破坏原始数据:前端传
{"name": "O'Reilly"},Filter改成O'Reilly后,JSON解析直接报JsonParseException - 绕过方式极多:攻击者改用
1=1/**/UNION/**/SELECT、Unicode编码、宽字节注入,纯字符替换完全无效
真正该做的三件事
防御SQL注入不是加一层Filter就能解决的,核心是切断拼接路径:
- 所有数据库访问必须用
PreparedStatement,参数用setString()等方法绑定,让JDBC驱动负责底层转义 - 如果非要用动态SQL(如MyBatis),禁用
${},只用#{};检查所有@SelectProvider类是否拼接了未校验的字符串 - 对用户输入做最小化白名单过滤(如手机号只允许数字,用户名限制长度和字符集),而不是“转义”——后者永远追不上新漏洞变种
Filter能做的有限但关键的事
Filter唯一合理介入点是日志和告警:记录可疑请求特征,不修改数据。
- 扫描
request.getQueryString()和request.getInputStream()(需缓存body)中是否含UNION SELECT、EXEC(、@@version等高危模式 - 匹配到时,写入审计日志并返回
400 Bad Request,但不要尝试“清理”内容 - 注意性能:正则匹配开销大,建议用
contains()快速筛出明显恶意串,再用精确正则二次确认
真正的SQL安全不在Web层,而在你写executeUpdate()那行代码之前有没有用?占位符——Filter连这行代码都看不见。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











