MST

星途 面试题库

面试题:Java安全性测试之SQL注入防范

在Java Web开发中,经常会面临SQL注入的风险。假设你正在使用JDBC进行数据库操作,如何防止SQL注入?请举例说明使用预编译语句(PreparedStatement)的方式及其优势。
16.4万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

防止SQL注入的方法 - 使用预编译语句(PreparedStatement)

  1. 方式举例: 假设要查询用户表中特定用户名和密码的用户信息。 普通 Statement 方式(存在SQL注入风险):
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class SQLInjectionExample {
    public static void main(String[] args) {
        String username = "test'; DROP TABLE users; --";
        String password = "anyPassword";
        String url = "jdbc:mysql://localhost:3306/mydb";
        String dbUser = "root";
        String dbPassword = "password";

        try (Connection conn = DriverManager.getConnection(url, dbUser, dbPassword);
             Statement stmt = conn.createStatement()) {
            String sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
            ResultSet rs = stmt.executeQuery(sql);
            if (rs.next()) {
                System.out.println("User found!");
            } else {
                System.out.println("User not found.");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

上述代码中,如果恶意用户输入 test'; DROP TABLE users; -- 作为用户名,可能会导致 users 表被删除。

使用 PreparedStatement 方式(防止SQL注入):

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

public class PreventSQLInjectionExample {
    public static void main(String[] args) {
        String username = "test'; DROP TABLE users; --";
        String password = "anyPassword";
        String url = "jdbc:mysql://localhost:3306/mydb";
        String dbUser = "root";
        String dbPassword = "password";

        try (Connection conn = DriverManager.getConnection(url, dbUser, dbPassword);
             PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM users WHERE username =? AND password =?")) {
            pstmt.setString(1, username);
            pstmt.setString(2, password);
            ResultSet rs = pstmt.executeQuery();
            if (rs.next()) {
                System.out.println("User found!");
            } else {
                System.out.println("User not found.");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  1. 优势
    • 防止SQL注入PreparedStatement 会将传入的参数作为普通字符串处理,而不是SQL语句的一部分。所以即使参数中包含SQL关键字,也不会被当作SQL指令执行,从而有效防止了SQL注入攻击。
    • 性能优化:数据库可以对 PreparedStatement 进行缓存和预编译。当多次执行相同的 PreparedStatement 时,数据库不需要每次都重新编译SQL语句,提高了执行效率。
    • 代码可读性和维护性PreparedStatement 使用占位符(?)来代替具体的参数值,使SQL语句的结构更清晰,易于理解和维护。例如在复杂的SQL语句中,通过占位符可以清楚地看到参数的位置和作用,而不需要在字符串拼接中查找参数。