面试题答案
一键面试防止SQL注入的方法 - 使用预编译语句(PreparedStatement)
- 方式举例:
假设要查询用户表中特定用户名和密码的用户信息。
普通
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();
}
}
}
- 优势:
- 防止SQL注入:
PreparedStatement
会将传入的参数作为普通字符串处理,而不是SQL语句的一部分。所以即使参数中包含SQL关键字,也不会被当作SQL指令执行,从而有效防止了SQL注入攻击。 - 性能优化:数据库可以对
PreparedStatement
进行缓存和预编译。当多次执行相同的PreparedStatement
时,数据库不需要每次都重新编译SQL语句,提高了执行效率。 - 代码可读性和维护性:
PreparedStatement
使用占位符(?
)来代替具体的参数值,使SQL语句的结构更清晰,易于理解和维护。例如在复杂的SQL语句中,通过占位符可以清楚地看到参数的位置和作用,而不需要在字符串拼接中查找参数。
- 防止SQL注入: