位置:首页 > SQL > 如何在 Java 8 项目中防止 SQL 注入

如何在 Java 8 项目中防止 SQL 注入

时间:2026-08-25  |  作者:怪兽小助手  |  阅读:0

PreparedStatement是唯一可靠的第一道防线,它通过预编译将SQL结构与参数彻底分离,使用户输入(如' OR 1=1 --)仅作为字符串值处理,绝不参与语法解析;必须用占位并配合setXxx()绑定,严禁字符串拼接或滥用${}。

如何在Ja va 8项目中防止SQL注入

PreparedStatement 是唯一可靠的第一道防线

可别轻信“加个过滤器就能防止注入”这种说法。在Ja va 8中,要防止SQL注入,PreparedStatement可不是可选项,而是强制要求。它能将SQL结构与参数彻底分离,数据库在预编译阶段就锁定了语句的骨架,后续传入的任何内容(哪怕包含 ' OR 1=1 --)都仅被当作字符串值来处理,根本不会参与语法解析。

常见错误现象:用 Statement 拼接 "SELECT * FROM user WHERE id = " + userId,即使 userId 是数字类型,攻击者仍可通过类型绕过(如传入 1; DROP TABLE user;)触发堆叠查询。

  • 必须用 占位,再通过 pstmt.setString(1, value)pstmt.setLong(2, id) 等方法绑定,不能留空或跳过设置
  • 批量操作优先用 addBatch() + executeBatch(),避免循环中反复 prepare
  • 不要试图在占位符外做“手动转义”,比如先调 StringEscapeUtils.escapeSql() 再拼接——这既多余又可能引入新漏洞

MyBatis 里 #{} 和 ${} 的边界必须划死

#{} 在 MyBatis 里等价于 PreparedStatement 参数绑定,安全;${} 是纯文本替换,等同于字符串拼接,高危。很多项目崩溃就倒在把 ${} 用错了地方。

使用场景差异很明确:

  • #{} 用于所有值类参数:WHERE name = #{name}AND status IN (#{status1}, #{status2})
  • ${}仅限白名单控制的元数据:表名、列名、ORDER BY 字段。例如 SELECT * FROM ${tableName},但必须配套校验:if (!List.of("user", "order", "product").contains(tableName)) throw new IllegalArgumentException();
  • 绝对禁止 ${} 出现在 WHEREVALUES 或任何能带入用户输入值的位置

异常信息不脱敏 = 主动交出数据库结构

SQL执行一旦失败,SQLException.getMessage()往往会包含敏感细节。像MySQL可能会输出Unknown column 'pwd_hash' in 'where clause',PostgreSQL则会报relation "users_backup" does not exist。这些信息对于攻击者来说,就如同探路的坐标一般。

生产环境必须切断原始消息透出路径:

  • HTTP 响应体统一返回 {"code": 500, "message": "操作失败,请稍后重试"},不带任何技术词
  • 日志记录用 e.getSQLState()(如 23505 表示唯一约束冲突)和 e.getErrorCode()(驱动特有码),它们稳定、无上下文
  • 严禁 e.printStackTrace() 写入公开可查的日志文件,尤其不能出现在监控页面或 API 返回体里

输入验证不是补丁,是前置闸机

验证不是为了“让 SQL 更安全”,而是减少无效请求、降低异常触发概率、堵住非参数化路径的漏网之鱼。它和 PreparedStatement 是两层独立防护,不能互相替代。

关键点在于语义化校验,不是关键词过滤:

  • ID 类参数直接转类型:Long.parseLong(idStr),捕获 NumberFormatException 拒绝,不留给 JDBC 解析
  • 邮箱、手机号用正则白名单:^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$,不依赖前端 JS 校验
  • 分页参数设硬上限:Math.min(pageSize, 100),防恶意大值拖垮数据库
  • 禁用全局“SQL 关键词黑名单”(如拦截 union select drop),规则易绕过且干扰正常业务字段(比如用户名含 “select”)

最危险的疏忽,是以为用了 MyBatis 就万事大吉——只要碰上一个 ${} 或一次手写 Statement,整套防线就形同虚设。

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多