Java JDBC 控制台用户登录测试 及 登录存在SQL注入的解决
实现功能:
1.用户登录
2.java连接数据库验证,控制台显示成功或失败
idea 新建java空项目,新建测试类LoginTest
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;
//单独定义变量
String loginName =userLoginInfo.get("loginName");
String loginPwd = userLoginInfo.get("loginPwd");
//JDBC代码
Connection conn =null;
Statement stmt=null;
ResultSet re =null;
try {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取链接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/user","root","root");
//3.获取数据库操作对象
stmt = conn.createStatement();
//4.执行SQL
String sql = "select * from t_user where loginName = '"+loginName+"' and loginPwd = '"+loginPwd+"' ";
//以上正好完成了SQL语句的拼接,以下代码的含义是发送SQL语句给DBMS,DBMS进行SQL编译
re = stmt.executeQuery(sql);//执行查询,将SQL传过来
//5.处理结果集
if(re.next()){
//登陆成功
loginSuccess = true;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
//6.资源释放
if(re!=null) {
try {
re.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt !=null) {
try {
re.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null) {
try {
re.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return loginSuccess;
}
private static Map<String, String> initUI() {
Scanner s = new Scanner(System.in);
//读取用户名
System.out.print("用户名:");
String loginName = s.nextLine();
//读取密码
System.out.println("密码:");
String loginPwd =s.nextLine();
//将数据组装到Map中
Map<String,String> userLoginInfo = new HashMap<>();
userLoginInfo.put("loginName",loginName);
userLoginInfo.put("loginPwd",loginPwd);
//返回Map
return userLoginInfo;
}
执行结果:
登陆成功
存在问题 : SQL注入
用户名:qwer
密码:qwer' or '1'='1
此时能够能录成功,这种现象被称为SQL注入
导致SQL注入的根本原因:
用户输入的信息中含有SQL语句的关键字,并且这些关键字参与SQL的编译过程,导致SQL语句的原意被扭曲,进而达到SQL注入
其中
String sql = "select * from t_user where loginName = '"+loginName+"' and loginPwd = '"+loginPwd+"' ";
re = stmt.executeQuery(sql);//执行查询,将SQL传过来
上行代码正好完成了SQL语句的拼接,下行代码的含义是发送SQL语句给DBMS,DBMS进行SQL编译,正好将用户提供的“非法信息”编译进去,扭曲了原有SQL语句
解决方法:
只要用户提供的信息不参与编译过程,问题就解决了,使用PrepareStatement替换Statement
新建类LoginTest02
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;
//单独定义变量
String loginName =userLoginInfo.get("loginName");
String loginPwd = userLoginInfo.get("loginPwd");
//JDBC代码
Connection conn =null;
//这里使用prepareStatement(预编译的数据库操作对象)
PreparedStatement ps=null;
ResultSet re =null;
try {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取链接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/user","root","root");
//3.获取预编译的数据库操作对象
String sql = "select * from t_user where loginName = ? and loginPwd = ? ";
//SQL语句的框子。问号是占位符,不加引号。一号问号接受一个值
// 程序执行到此处,会发送SQL语句框子给DBMS,然后DBMS进行SQL语句的预先编译
//给占位符?传值 (第一个问号下标是1,第二个问号下标是2,JDBC所有下标 从1开始)
//4.执行SQL
ps = conn.prepareStatement(sql);
ps.setString(1,loginName);
ps.setString(2,loginPwd);
re = ps.executeQuery();
//5.处理结果集
if(re.next()){
//登陆成功
loginSuccess = true;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
//6.资源释放
if(re!=null) {
try {
re.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(ps !=null) {
try {
re.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null) {
try {
re.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return loginSuccess;
}
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中
Map<String,String> userLoginInfo = new HashMap<>();
userLoginInfo.put("loginName",loginName);
userLoginInfo.put("loginPwd",loginPwd);
//返回Map
return userLoginInfo;
}
执行结果:
SQL注入问题解决,登录正常
解决SQL注入问题的关键:
用户提供的信息中心即使含有SQL语句的关键字,但这些关键字没有参与编译,只要用户提供的信息不参与编译过程,问题就解决了
要想用户信息不参与SQL语句的编译,那么必须使用java.sql.PreparedStatement
PreparedStatement接口继承了java.sql.Statement,是属于预编译的数据库操作对象
原理是预先对SQL语句框架进行编译,然后再给SQL传值
进行降序或者升序查询的时候,使用SQL语句拼接,可以使用Statement
本文来自博客园,作者:大星星不见了,转载请注明原文链接:https://www.cnblogs.com/dxxbjl/p/15084523.html