PrepardeStatement解决SQL注入问题
备注
(该篇文章也属于下列文章的一个进一步引申)
-
原本的sql注入问题讲解见:JDBC-02:操作访问数据库时使用Statement操作数据表的弊端
-
文章中的方法test3的详细讲解在:JDBC-04:PreparedStatement针对不同表的通用查询操作
User类代码
package com.jsm1.java1;
public class User {
private String user;
private String password;
public User() {
}
public User(String user, String password) {
super();
this.user = user;
this.password = password;
}
@Override
public String toString() {
return "User [user=" + user + ", password=" + password + "]";
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
测试代码
package com.jsm4;
import com.jsm1.java1.User;
import com.util.JDBCUtils;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.Scanner;
public class sqlTest {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入用户名:");
String user = scanner.nextLine();
System.out.print("请输入密码:");
String password = scanner.nextLine();
// 并且存在SQL注入的问题:
/*
SELECT user,password FROM user_table WHERE user='1' or ' AND password= '=1 or '1' = '1'
*/
//需要拼写sql语句
String sql="SELECT user,password FROM user_table WHERE user= ? AND password = ? ";
User user1 = test3(User.class,sql,user,password);
if (user1!=null){
System.out.println("登录成功!!");
}else {
System.out.println("登录失败!");
}
}
public static <T>T test3(Class<T> clazz,String sql, Object...args) throws Exception {
Connection conn = JDBCUtils.getCollections();
PreparedStatement ps = conn.prepareStatement(sql);
for (int i = 0; i <args.length ; i++) {
ps.setObject(i+1,args[i]);//填充占位符
}
ResultSet rs = ps.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
if (rs.next()){
T t = clazz.newInstance();
for (int i = 0; i <columnCount ; i++) {
Object value = rs.getObject(i + 1);
String columnLabel = rsmd.getColumnLabel(i+1);
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t,value);
}
return t;
}
JDBCUtils.closeResource(conn,ps,rs);
return null;
}
}
运行结果
解决sql问题的原理
先见PrepardeStatement的API
这里说到了,预编译sql语句,这里的sql语句:
SELECT user,password FROM user_table WHERE user= ? AND password = ?
原理:在填充占位符之前,PrepardeStatement就已经说明了谁AND谁的关系,也就是且的关系,在填占位符之前和之后,这种关系是不会改变的,statement不靠谱是因为它虽然也想表达谁且谁的关系,但是它没有预编译的过程,所以它直接拿一整个sql语句去执行,在sql注入之后,就改变了原本的关系