Java代码SQL注入问题咨询:含字符串拼接漏洞的主方法分析
技术分析与修复方案:SQL注入漏洞(字符串拼接导致)
一、漏洞成因技术分析
咱们先拆解下你这段代码里的核心风险:
在else分支中,你直接把subName变量通过字符串拼接的方式嵌入到SQL条件里:
name = "= LOWER('" + subName + "')";
这种写法完全没有对变量做任何安全防护——哪怕现在subName是硬编码的"abhi",但如果后续这个变量变成用户可控的输入(比如前端传参、外部配置),攻击者就能构造恶意值篡改SQL逻辑。
举个例子,如果subName被修改为:
abhi'); DROP TABLE your_target_table; --
拼接后的SQL条件就会变成:
= LOWER('abhi'); DROP TABLE your_target_table; --')
数据库执行时会先完成原查询,紧接着执行DROP TABLE语句,直接造成数据丢失——这就是典型的SQL注入漏洞,攻击者可以通过构造恶意输入,执行任意未授权的数据库操作。
哪怕flag=true时的LIKE '%'现在看起来没问题,一旦flag的判断逻辑和用户输入挂钩,同样会引入注入风险。
二、修复方案:使用参数化查询(PreparedStatement)
解决SQL注入的行业标准方案就是用PreparedStatement替代Statement,它会把SQL逻辑和参数值完全分离:数据库先编译固定的SQL模板,再安全地注入参数值,从根源上避免恶意输入被解析成SQL指令。
修复后的完整代码示例:
public static void main(String[] args) { boolean flag = false; String subName = "abhi"; try { Class.forName("org.postgresql.Driver"); // 建议用try-with-resources自动关闭资源,避免泄漏 try (Connection c = DriverManager.getConnection("url","user", "password")) { String queryTemplate; if(flag){ queryTemplate = "SELECT * FROM your_table WHERE your_column LIKE ?"; } else { // 把LOWER()移到列上,或在应用层处理subName的小写(根据索引情况选择) queryTemplate = "SELECT * FROM your_table WHERE LOWER(your_column) = ?"; } // 预编译SQL模板 try (PreparedStatement ps = c.prepareStatement(queryTemplate)) { // 根据逻辑设置参数,JDBC自动处理转义 if(flag){ ps.setString(1, "%"); } else { ps.setString(1, subName.toLowerCase()); } // 执行查询 try (ResultSet rs = ps.executeQuery()) { // 后续处理ResultSet逻辑... } } } } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } }
关键修复点说明:
- 分离SQL与参数:用
?作为占位符代替字符串拼接,数据库会将占位符位置的内容当作纯数据处理,不会解析为SQL指令 - 预编译机制:
PreparedStatement会预先编译SQL模板,不仅更安全,还能提升重复执行相同结构SQL的性能 - 参数安全注入:通过
setString等方法设置参数,JDBC会自动处理特殊字符的转义,彻底避免恶意输入破坏SQL结构 - 资源自动管理:用
try-with-resources语法自动关闭连接、Statement、ResultSet,避免手动关闭遗漏导致的资源泄漏
额外建议
- 永远不要信任任何用户可控的输入,哪怕是内部生成的变量,也要假设它可能被篡改
- 优先使用ORM框架(如MyBatis、Hibernate),它们底层基于参数化查询,能进一步降低手动编写SQL的出错概率
- 如果必须手动写SQL,严格禁止任何形式的字符串拼接,所有变量都通过
PreparedStatement的参数方法传入
内容的提问来源于stack exchange,提问作者ashim panda




