面试题答案
一键面试SQL注入漏洞可能出现的代码场景
- 使用Statement时:Statement在执行SQL语句时,将用户输入的数据直接拼接到SQL语句字符串中。如果用户输入的数据包含恶意的SQL语句片段,就会导致SQL注入漏洞。例如:
String username = request.getParameter("username");
String password = request.getParameter("password");
String sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);
这里如果username
或password
的值被恶意构造(如username = "any' OR '1'='1"
),整个SQL语句的逻辑就会被改变,可能导致非法数据访问。
Statement和PreparedStatement的区别
- SQL语句编译方式:
- Statement:每次执行SQL语句时,数据库都要重新编译SQL语句,性能较低。而且由于SQL语句是动态拼接的,无法预编译,容易导致SQL注入。
- PreparedStatement:SQL语句在创建
PreparedStatement
对象时就被预编译并存储在数据库中。执行时,只需要传入参数,数据库直接使用预编译的语句,性能较高。并且参数和SQL语句分离,有效防止SQL注入。
- 安全性:
- Statement:由于直接拼接用户输入数据到SQL语句,对用户输入没有任何防护,极易受到SQL注入攻击。
- PreparedStatement:通过占位符(
?
)来代替实际参数,数据库会将参数当作普通数据处理,而不是SQL语句的一部分,从而防止SQL注入。
正确使用PreparedStatement预防SQL注入漏洞示例
String username = request.getParameter("username");
String password = request.getParameter("password");
String sql = "SELECT * FROM users WHERE username =? AND password =?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, username);
preparedStatement.setString(2, password);
ResultSet resultSet = preparedStatement.executeQuery();
在上述示例中,使用?
作为占位符,通过setString
方法设置参数值,无论username
和password
的值是什么,都不会改变SQL语句的结构,从而有效预防SQL注入漏洞。