MST

星途 面试题库

面试题:Java中JDBC连接MySQL数据库时,如何处理SQL注入问题

在Java使用JDBC连接MySQL数据库场景下,阐述为什么会存在SQL注入风险,并说明至少两种有效处理SQL注入问题的方法及具体实现代码示例。
22.0万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

SQL注入风险原因

在使用JDBC连接MySQL数据库时,如果直接将用户输入的数据拼接到SQL语句中,就会产生SQL注入风险。因为用户输入的数据可能包含恶意的SQL语句片段,这些片段会改变原本SQL语句的逻辑和执行意图,导致数据库的信息泄露、数据被篡改或删除等安全问题。例如,原本的SQL查询语句是 SELECT * FROM users WHERE username = '${userInput}' AND password = '${passwordInput}',如果 userInput 被恶意输入为 ' OR '1' = '1,整个SQL语句就会变为 SELECT * FROM users WHERE username = '' OR '1' = '1' AND password = '${passwordInput}',这样无论密码是否正确,都会返回所有用户数据。

处理SQL注入问题的方法及代码示例

1. 使用PreparedStatement

PreparedStatement 是预编译的SQL语句对象,它将SQL语句和参数分开处理,避免了直接拼接用户输入数据带来的风险。

示例代码:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class JdbcExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydb";
        String user = "root";
        String password = "password";
        String username = "testUser";
        String passwordInput = "testPassword";

        try (Connection connection = DriverManager.getConnection(url, user, password)) {
            String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
            try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
                preparedStatement.setString(1, username);
                preparedStatement.setString(2, passwordInput);
                try (ResultSet resultSet = preparedStatement.executeQuery()) {
                    if (resultSet.next()) {
                        System.out.println("User found!");
                    } else {
                        System.out.println("User not found.");
                    }
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

2. 使用ORM框架(以Hibernate为例)

ORM(对象关系映射)框架将Java对象与数据库表进行映射,通过框架的操作方法来执行数据库操作,而不是直接编写SQL语句,大大降低了SQL注入的风险。

首先,需要添加Hibernate相关依赖(以Maven为例):

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.6.10.Final</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.31</version>
</dependency>

示例代码:

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateExample {
    public static void main(String[] args) {
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();

        String username = "testUser";
        String password = "testPassword";

        // 假设User是映射到users表的实体类
        User user = session.createQuery("FROM User WHERE username = :username AND password = :password", User.class)
                .setParameter("username", username)
                .setParameter("password", password)
                .uniqueResult();

        if (user != null) {
            System.out.println("User found!");
        } else {
            System.out.println("User not found.");
        }

        session.close();
        sessionFactory.close();
    }
}

这里 User 是一个根据数据库 users 表映射生成的Java实体类,Hibernate通过 createQuery 方法并使用命名参数的方式来避免SQL注入。