目录
一、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 ? "登录成功" : "登录失败");
}
/**
* 用户登录
* @param userLoginInfo 用户登录信息
* @return true表示登录成功,false表示登录失败
*/
private static boolean login(Map<String, String> userLoginInfo) {
boolean loginSuccess = false;
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2、获取连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase","root","146");
// 3、获取数据库操作对象
stmt = conn.createStatement();
// 4、执行sql语句
String sql = "select * from t_user where userName = '"+ userLoginInfo.get("userName")+ "' and userPassword = '" + userLoginInfo.get("userPassword")+ "'";
rs = stmt.executeQuery(sql);
// 5、处理结果集
if(rs.next()) {
loginSuccess = true;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
// 6、释放资源
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;
}
/**
* 初试化界面
* @return 用户输入的用户名和密码等登录信息
*/
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的一边恒等,输入的所有内容会直接传入该语句并进行拼接,该查询语句总是正确,所以密码是错误的也能够登录系统。
二、解决方案
//使用preparement接口,可以进行预编译。
//预编译时把,输入框传入的数据强制转化为非sql关键字的字符串或者其他数据类型,这样就避免了sql注入.、
//代码如下:
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{
// 6、释放资源
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注入现象没有发生