1.什么是SQL攻击。
在需要用户输入的地方,用户输入的是SQL语句的片段,最终用户输入的SQL片段与我们DAO中写的SQL语句合成一个完整的SQL语句!例如用户在输入用户名以及登陆密码都是SQL语句时,我们的程序就会将其嵌入到我们的SQL语句中,最终可能出现数据库的错误。
2.PreparedStatement
1)它是Statement接口的子接口;
2)强大之处
2.1)防SQL攻击。
2.2)提高代码的可读性。
2.3) 提高效率
实例:
public boolean login(String username,String password) throws Exception{
ResultSet re = null;
Connection con = null;
Statement stmt = null;
String sql = "select * from users where Id = '"
+username+"' and Password = '"+password+"'";
boolean result = false;
try{
//设置四大参数
String driverClassName = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/timebookstore";
String sqlUserName = "***";
String sqlPassword = "123456";
//加载类
Class.forName(driverClassName);
//连接数据库获取Connection对象
con = DriverManager
.getConnection(url,sqlUserName,sqlPassword);
//获取Statement,用于向数据库发送SQL语句
stmt = con.createStatement();
//发送查询语句
re=stmt.executeQuery(sql);
result = re.next();
}catch(Exception e){
e.printStackTrace();
}finally{
if(re != null)re.close();
if(stmt != null)stmt.close();
if(con != null)con.close();
}
return result;
}
@Test
public void fun2() throws Exception{
String username = "abc";
String password = "123";
System.out.println(login(username,password));
}
控制台输出的结果是false,表示验证不成功。但是如果用户名和密码改为如下:
@Test
public void fun2() throws Exception{
String username = "abc' or 'a' = 'a";
String password = "123' or 'a' = 'a";
System.out.println(login(username,password));
}
也即完整的sql语句为:
select * from users where Id = 'abc' or 'a' = 'a' and Password = '123' or 'a' = 'a'
很明显这一句查询语句返回表中的所有内容,所以结果是true。这就是sql攻击.
下面的例子使用PreparedStatement防止sql攻击。
public boolean login(String username,String password) throws Exception{
ResultSet re = null;
Connection con = null;
PreparedStatement pstmt = null;
String sql = "select * from users where Id = ? and password = ?";
boolean result = false;
try{
//设置四大参数
String driverClassName = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/timebookstore";
String sqlUserName = "***";
String sqlPassword = "123456";
//加载类
Class.forName(driverClassName);
//连接数据库获取Connection对象
con = DriverManager
.getConnection(url,sqlUserName,sqlPassword);
//获取PreparedStatement,用于向数据库发送SQL语句
pstmt = con.prepareStatement(sql);
//设置sql的参数
pstmt.setString(1, username);
pstmt.setString(2,password);
//执行sql语句
re=pstmt.executeQuery();
result = re.next();
}catch(Exception e){
e.printStackTrace();
}finally{
if(re != null)re.close();
if(pstmt != null)pstmt.close();
if(con != null)con.close();
}
return result;
}
@Test
public void fun2() throws Exception{
String username = "abc' or 'a' = 'a";
String password = "123' or 'a' = 'a";
System.out.println(login(username,password));
}
使用PreparedStatement的结果是false,与我们预期的一样了。
由上面的例子可以看出使用PreparedStatement,编写的sql语句更加直观,还可以防sql攻击。
String sql = "select * from users where Id = '"+username+"' and password = '"+password+"'";//Statement
String sql = "select * from users where Id = ? and password = ?";//PreparedStatement
?号表示参数,下面有设置该参数的代码。
pstmt = con.prepareStatement(sql);
//设置sql的参数
pstmt.setString(1, username);
pstmt.setString(2,password);