登录sql注入问题

会被sql注入的代码

当密码有类似fdsa' or '1'='1,会被sql注入,原因是字符串拼接时1=1这种类似条件会执行在sql语句中,这时就会被sql注入密码输错也能登录成功,要避免此问题不能用Statement,要用PreparedStatement。PreparedStatement会预编译,然后确定值得正确性才执行sql语句。

不安全代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package os;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Scanner;

public class login {
public static void main(String[] args) {
//初始化UI
Map<String,String> userLoginInfo=initUI();
//验证用户名和密码
boolean loginSuccess = login(userLoginInfo);
System.out.println(loginSuccess?"登录成功":"登录失败");
}
private static boolean login(Map<String,String> data)
{
ResourceBundle bundle=ResourceBundle.getBundle("JDBC");
Connection conn=null;
Statement stm=null;
ResultSet rt=null;
try {
Class.forName(bundle.getString("driver"));
String url=bundle.getString("url");
String name=bundle.getString("name");
String pw=bundle.getString("pw");
conn= DriverManager.getConnection(url,name,pw);
stm=conn.createStatement();
String sql="select * from t_logintest where 登录名='"+data.get("用户名")+"' and 登录密码='"+data.get("密码")+"'";
rt=stm.executeQuery(sql);
if(rt.next())
{
return true;
}

} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}finally {
if(rt!=null)
{
try {
rt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stm!=null)
{
try {
stm.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null)
{
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}


}
return false;
}

/**
* 初始化用户界面
* @return返回用户名和密码
*/
private static Map<String, String> initUI() {
Scanner sc=new Scanner(System.in);
System.out.println("请输入用户名:");
String userName=sc.nextLine();
System.out.println("请输入密码:");
String pw=sc.nextLine();
Map<String,String> userLoginInfo= new HashMap<>();
userLoginInfo.put("用户名",userName);
userLoginInfo.put("密码",pw);
return userLoginInfo;
}


}

不会被sql注入的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package os;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Scanner;
//PreparedStatement的原理是预先对SQL语句的框架进行编译,然后再给SQL语句传值
public class loginplus {
public static void main(String[] args) {
//初始化UI
Map<String,String> userLoginInfo=initUI();
//验证用户名和密码
boolean loginSuccess = login(userLoginInfo);
System.out.println(loginSuccess?"登录成功":"登录失败");
}
private static boolean login(Map<String,String> data)
{
ResourceBundle bundle=ResourceBundle.getBundle("JDBC");
Connection conn=null;
PreparedStatement stm=null;
ResultSet rt=null;
try {
Class.forName(bundle.getString("driver"));
String url=bundle.getString("url");
String name=bundle.getString("name");
String pw=bundle.getString("pw");
conn= DriverManager.getConnection(url,name,pw);
String sql="select * from t_logintest where 登录名=? and 登录密码=?";//sql语句框子,一个问号表示一个占位符一个问号表示接收一个值,没有单引号
stm=conn.prepareStatement(sql);
//给问号传值,第一个问号小标为1,第二个问号下标为2...
stm.setString(1,data.get("用户名"));
stm.setString(2,data.get("密码"));
rt=stm.executeQuery();
if(rt.next())
{
return true;
}

} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}finally {
if(rt!=null)
{
try {
rt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stm!=null)
{
try {
stm.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null)
{
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}


}
return false;
}

/**
* 初始化用户界面
* @return返回用户名和密码
*/
private static Map<String, String> initUI() {
Scanner sc=new Scanner(System.in);
System.out.println("请输入用户名:");
String userName=sc.nextLine();
System.out.println("请输入密码:");
String pw=sc.nextLine();
Map<String,String> userLoginInfo= new HashMap<>();
userLoginInfo.put("用户名",userName);
userLoginInfo.put("密码",pw);
return userLoginInfo;
}


}
//PrepareedStatement(传值时会做检查) 执行效率高,编译一次执行n次,Statement 编译一次执行一次

附录properties文件

1
2
3
4
driver=写驱动
name=写用户名
url=数据库url
pw=写密码