什么是SQL注入?
- 用户输入的信息包含了SQL语句关键字,并且这些关键字参与SQL语句的编译过程,导致SQL语句的愿意被扭曲,进而达到SQL注入。
String sql = "select * from t_user where loginName = '" + loginName + "'" +
"and loginPwd = " + "'" + loginPwd + "'";
rs = statement.executeQuery(sql);
上述SQL语句设定为输入正确的登录名和密码才能获取用户信息,但是若是输入一个不存在的登录名:dsds,以及输入密码:ds’ or ‘1’='1,也可获取到用户信息,这是因为拼接了loginPwd后,SQL语句的愿意被篡改了:
// '1'='1' 永远成立
String sql = "select * from t_user where loginName = 'dsds' and loginPwd = 'ds' or '1'='1'";
这就是SQL注入。
如何解决SQL注入?
- 使用户提供的信息不参与SQL语句的编译过程即可。
使用PreparedStatement接口替代Statement接口,PreparedStatement可以对SQL语句进行预编译,从而使得用户提供的信息不参与SQL语句的编译过程,避免SQL注入的发生。
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Scanner;
public class JDBCTest02 {
public static void main(String[] args) {
Map<String, String> userInfo = initUI();
boolean loginSuccess = login(userInfo);
if (loginSuccess) {
System.out.println("登陆成功!");
}else {
System.out.println("登陆失败!");
}
}
private static boolean login(Map<String, String> userInfo) {
String loginName = userInfo.get("loginName");
String loginPwd = userInfo.get("loginPwd");
boolean loginResult = false;
ResourceBundle bundle = ResourceBundle.getBundle("config");
String driver = bundle.getString("driver");
String url = bundle.getString("url");
String user = bundle.getString("user");
String passWord = bundle.getString("passWord");
ResultSet rs = null;
PreparedStatement ps = null;
Connection con = null;
try {
Class.forName(driver);
con = DriverManager.getConnection(url, user, passWord);
// ?为占位符。
String sql = "select * from t_user where loginName = ? and loginPwd = ?";
// 创建数据库操作对象,同时传入SQL语句并对其编译。
ps = con.prepareStatement(sql);
// 编译完成后,给占位符传入值,第一个占位符下标为1,第二个占位符下标为2。
ps.setString(1, loginName);
ps.setString(2, loginPwd);
// 执行SQL语句
rs = ps.executeQuery();
if (rs.next()) {
loginResult = true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return loginResult;
}
private static Map<String, String> initUI() {
Scanner s = new Scanner(System.in);
System.out.print("登录名:");
String loginName = s.nextLine();
System.out.print("密码:");
String loginPwd = s.nextLine();
Map<String, String> map = new HashMap<>();
map.put("loginName", loginName);
map.put("loginPwd", loginPwd);
return map;
}
}
修改程序后,再次输入ds’ or ‘1’='1,将提示登陆失败。