Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > SQL注入

SQL注入的风险与解决方案实战解析

作者:网罗开发

这篇文章主要为大家详细介绍了SQL注入的风险分析与解决方案的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

前言

在日常开发中,数据库操作几乎是绕不开的环节。很多同学写查询语句的时候,习惯直接用字符串拼接,比如:

String sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";

乍一看挺正常,但一旦碰上心怀不轨的攻击者,后果就可能非常严重。这就是我们常说的 SQL 注入 问题。

什么是 SQL 注入

SQL 注入的本质就是:

用户的输入被直接拼接到 SQL 语句中,没有做任何防护,导致数据库把攻击者的输入当成真正的 SQL 指令去执行。

举个最经典的例子:

如果登录接口这样写:

String username = "admin";
String password = "' OR '1'='1";  // 攻击者输入的内容
String sql = "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'";
System.out.println(sql);

拼接后的 SQL 就变成了:

SELECT * FROM users WHERE username='admin' AND password='' OR '1'='1'

这一句 OR '1'='1' 永远成立,所以攻击者轻轻松松绕过了密码验证,直接登录成功。

真实场景下的危害

别以为这只是理论,现实中因为 SQL 注入出问题的案例太多了。常见危害包括:

所以在企业开发里,SQL 注入算是基础中的基础,必须提前预防。

常见解决方案

那我们该怎么防范呢?有几种常见的方式:

1. 使用 PreparedStatement

PreparedStatement 是 JDBC 提供的预编译语句对象。它会先把 SQL 模板交给数据库编译好,然后再传入参数。这样参数和 SQL 逻辑严格分离,用户输入就不会被当成 SQL 指令执行。

Demo 代码

import java.sql.*;

public class SafeLoginDemo {
    public static void main(String[] args) throws Exception {
        String url = "jdbc:mysql://localhost:3306/testdb";
        String user = "root";
        String pass = "123456";

        String inputUser = "admin";
        String inputPass = "' OR '1'='1";

        Connection conn = DriverManager.getConnection(url, user, pass);

        String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
        PreparedStatement stmt = conn.prepareStatement(sql);
        stmt.setString(1, inputUser);
        stmt.setString(2, inputPass);

        ResultSet rs = stmt.executeQuery();

        if (rs.next()) {
            System.out.println("登录成功: " + rs.getString("username"));
        } else {
            System.out.println("用户名或密码错误");
        }

        rs.close();
        stmt.close();
        conn.close();
    }
}

这里无论用户输入什么奇怪的密码,数据库都会把它当成一个普通的字符串参数处理,而不是 SQL 逻辑。

2. MyBatis 使用#{}占位符

在 MyBatis 中,有两个写法经常被混淆:${}#{}

错误写法(容易被注入):

<select id="getUserByName" resultType="User">
    SELECT * FROM users WHERE username = '${username}'
</select>

正确写法(推荐使用):

<select id="getUserByName" resultType="User">
    SELECT * FROM users WHERE username = #{username}
</select>

这样就算有人传了 ' OR '1'='1 这样的输入,也只会作为字符串参数传入,不会破坏 SQL 逻辑。

3. 使用 ORM 框架封装查询

像 Hibernate、JPA 这类 ORM 框架,通常都已经封装了参数绑定逻辑,默认情况下就能避免注入风险。

比如用 Spring Data JPA:

public interface UserRepository extends JpaRepository<User, Long> {
    User findByUsernameAndPassword(String username, String password);
}

Spring Data JPA 底层会自动生成类似 PreparedStatement 的语句,所以基本不需要担心 SQL 注入问题。

总结

回过头来看,SQL 注入的核心原因是 “把用户输入当成 SQL 语句的一部分”
解决的思路就是 “参数化查询”,让 SQL 和用户输入严格分离。

落地建议:

到此这篇关于SQL注入的风险与解决方案实战解析的文章就介绍到这了,更多相关SQL注入内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文