一、SQL注入现象演示
且看一份Java实现登录功能的代码,其中使用了JDBC连接了t_user表,如果输入的姓名和密码在此表中存在,则显示登录成功。反之,则显示登录失败。
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class JDBCTest06 {
public static void main(String[] args) {
Map<String,String> userLoginInfo = initUI();
boolean loginSuccess = login(userLoginInfo);
System.out.println(loginSuccess ? "登录成功" : "登录失败");
}
private static boolean login(Map<String, String> userLoginInfo) {
boolean loginSuccess = false;
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase","root","146");
stmt = conn.createStatement();
String sql = "select * from t_user where userName = '"+ userLoginInfo.get("userName")+ "' and userPassword = '" + userLoginInfo.get("userPassword")+ "'";
rs = stmt.executeQuery(sql);
if(rs.next()) {
loginSuccess = true;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
return loginSuccess;
}
private static Map<String, String> initUI() {
Scanner s = new Scanner(System.in);
System.out.print("请输入用户:");
String userName = s.nextLine();
System.out.print("请输入密码:");
String userPassword = s.nextLine();
Map<String,String> userLoginInfo = new HashMap<>();
userLoginInfo.put("userName",userName);
userLoginInfo.put("userPassword",userPassword);
return userLoginInfo;
}
}
t_user表的结构和数据如图
当输入正确的姓名和密码时
SQL注入现象如下
当输入的密码中有or连接,且or的一边恒等,输入的所有内容会直接传入该语句并进行拼接,该查询语句总是正确,所以密码是错误的也能够登录系统。
二、解决方案
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class JBDCTest07 {
public static void main(String[] args) {
Map<String, String> userLoginInfo = initUI();
boolean loginSuccess = login(userLoginInfo);
System.out.println(loginSuccess ? "登录成功":"登录失败");
}
private static boolean login(Map<String, String> userLoginInfo) {
boolean loginSuccess = false;
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/MyDataBase?serverTimezone=GMT", "root", "aszhuo123");
String sql = "select * from t_user where name = ? and password = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, userLoginInfo.get("name"));
ps.setString(2, userLoginInfo.get("password"));
rs = ps.executeQuery();
if (rs.next()) {
loginSuccess = true;
}
} catch(ClassNotFoundException e) {
e.printStackTrace();
} catch(SQLException throwables){
throwables.printStackTrace();
} finally{
if (rs != null) {
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
return loginSuccess;
}
private static Map<String, String> initUI() {
Scanner s = new Scanner(System.in);
System.out.print("请输入用户:");
String userName = s.nextLine();
System.out.print("请输入密码:");
String userPassword = s.nextLine();
Map<String,String> userLoginInfo = new HashMap<>();
userLoginInfo.put("userName",userName);
userLoginInfo.put("userPassword",userPassword);
return userLoginInfo;
}
}
使用PreparedStatement关键字后,SQL注入现象没有发生
三、Statement的用途
Statement 支持 Sql 注入,当业务方面要求进行Sql语句拼接的,必须要用Statement关键字
例如:
Scanner s = new Scanner(System.in);
System.out.println("请输入desc 或 asc :");
String instruct = s.nextLine();
String sql = "select name from t_user order by name ?";
ps = conn.prepareStatement(sql);
ps.setString(1, instruct);
这块代码要求进行字符串拼接,使用PreparedStatement会报Sql语句出错,将PreparedStatement换成Statement即可解决。
|