sql预编译真的一劳永逸?

先序
先说一下预编译和参数化
预编译
指数据库在执行 SQL 前,预先编译 SQL 语句的结构(如 SELECT * FROM users WHERE id = ?),生成一个可重复使用的模板。
此时数据库已经确定了 SQL 的语法逻辑(比如 WHERE 后的条件结构),后续只需填充具体参数值。
参数化查询
指开发者将用户输入的数据通过参数传递给预编译后的 SQL 模板(如 ?、@id),确保输入数据不会改变 SQL 结构。
1.什么是sql注入
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
2.来防御sql注入最好的方法就是预编译
预编译原理:将SQL语句的结构(代码)与用户输入的数据完全分离,确保输入内容始终作为数据处理,而非可执行的SQL代码。
@@不安全的方式(拼接SQL):
String sql = "SELECT * FROM users WHERE name = '" + id + "'";
@@安全的方式(参数化查询):
String sql = "SELECT * FROM users WHERE name = ?";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setString(1, id);
这样即使id包含' or '1'='1,也会转译为普通字符串。
3.预编译的局限性
(1)只能处理 数据部分(WHERE 值、INSERT 值等),无法处理 SQL 结构部分(表名、列名、排序关键字等)。因为结构部分需要在预编译阶段确定,而参数是在执行阶段传入的。
比如表名,列名,order,group,limit等不可以参数化,被迫拼接字符串。
String sql = "SELECT * FROM " + table + " WHERE id = ?";
如果table为users;drop table users--,可能导致注入。
(2)二次注入
用户输入通过预编译安全地存入数据库,但后续从数据库读取该数据并未经处理直接拼接到新SQL语句中
4.如何保证预编译的有效性?
(1).对本能预编译的进行白名单过滤进行校验。
(2).防御二次注入,从数据库读取仍参数化。
(3).对输入进行严格校验。
(4).数据库账号最小权限,授予必要的权限即可,禁用FILE/DROP TABLE/CREATE/SELECT/INSERT.
5.SQL怎么防御
(1)预编译
(2)使用转义函数,对特殊字符转义。
(3)对输入进行严格校验。
(2)web应用防火墙,可能被绕过。
(3)数据库日志与监控,实时检测异常sql语句。
(4)定期进行安全测试,渗透测试,漏洞扫描。
(5)使用安全的ORM框架,ORM 生成的 SQL 是否参数化。
(6)数据库层封装业务逻辑,但需确保内部使用参数化,防止二次注入。
(7)密码信息加密存储。

posted @ 2025-04-05 18:38  大智不遇  阅读(152)  评论(1)    收藏  举报