像这样的声明
String query = "SELECT * FROM users WHERE userid ='"+ userid + "'" + " AND password='" + password + "'";
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(query);
符合SQL注入条件。但 PreparedStatement如何帮助防止SQL注入?请考虑以下情形:
PreparedStatement stmt = connection.prepareStatement("SELECT * FROM users WHERE userid=? AND password=?");
stmt.setString(1, userid);
stmt.setString(2, password);
ResultSet rs = stmt.executeQuery();
如果有人输入userId = "abc"
和password = "1=1"
会怎么样,因为这也会被视为有效的字符串......
答案 0 :(得分:6)
这可以保护您的确切方式取决于数据库,但有两个明显的选择:
在我看来,后者是一个更明智的解决方案,因为它允许数据库真正简单地缓存查询计划,认识到两个查询除参数值之外完全相同。我希望任何现代数据库都能在其原生通信协议中支持这一点。
答案 1 :(得分:3)
String query = "SELECT * FROM users WHERE userid ='"+ userid + "'" + " AND password='" + password + "'";
这里,如果您正在尝试演示sql注入,则为password的值 可能是这样的:'或1 = 1 OR''='
然后,发送到DB服务器执行的结果SQL是 -
SELECT * FROM users WHERE userid ='abc' AND password='' OR 1=1 OR ''=''
因此,无论用户名和密码如何,它都会从表中选择所有条目,因为 userid ='abc'AND password =''OR 1 = 1 OR''='' 总是如此。任何未经授权的人都可以访问所有用户的数据。
对于使用参数化预准备语句的第二语句 -
它将使用userid =“abc”和password =“'OR 1 = 1 OR''='”搜索表中的条目
由于预编译语句是在DB服务器中预先编译的,即首先是空白查询 SELECT * FROM users WHERE userid =? AND password =?被发送到服务器,服务器然后编译它,之后数据(参数)被单独发送到数据库(执行时)。数据,即password = 'OR 1 = 1 OR''='由JDBC Driver作为字符串文字发送。然后,DB服务器强制它用作有效参数而不是sql查询。
答案 2 :(得分:0)
用你的第二个例子,
PreparedStatement stmt = connection.prepareStatement("SELECT * FROM users" + " WHERE userid=? AND password=?"); stmt.setString(1, userid); stmt.setString(2, password); ResultSet rs = stmt.executeQuery();
如果有人输入userId =" abc"和密码=" 1 = 1",因为这也将被视为有效的字符串......
答案是是,但是正确转义的字符串文字。因此,密码必须实际上是1 = 1才能工作。需要明确的是,它不受SQL注入的影响,因为这些变量已正确绑定。
根据添加的PreparedStatement.setString(int, String)
Javadoc粗体,
将指定参数设置为给定的Java String值。当驱动程序将其发送到数据库时,驱动程序将其转换为SQL VARCHAR或LONGVARCHAR 值(取决于相对于驱动程序对VARCHAR值的限制的参数大小)。 / p>
答案 3 :(得分:0)
使用准备好的声明,您的请求将是:
SELECT * FROM users WHERE userId = \"abc\" AND password = \"1=1\"