目录
1.创建user表,其中表中有三个字段,分别是id(有自增功能), username, password。并插入三条数据。
那我们怎么该避免这种情况呢?这时候就需要用到PreparedStatement对象。
SQL注入:
由于jdbc程序在执行的过程中,sql语句在拼接时使用了由页面传入参数。如果用户恶意传入一些sql中的特殊关键字,就会导致sql语义发生变化,这种攻击方式就叫做sql注入。
用例子说明:
1.创建user表,其中表中有三个字段,分别是id(有自增功能), username, password。并插入三条数据。
create table user(
id int primary key auto_increment,
username varchar(50),
password varchar(50)
);
insert into user values(null,'张三','123');
insert into user values(null,'李四','456');
insert into user values(null,'王五','789');
效果图:
2.将数据库和Java连接并进行登录测试
package jdbc;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class login {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.println("您好,请输入用户名:");
// 获取用户输入的用户名
String username=s.nextLine().trim();
System.out.println("请输入密码:");
// 获取用户输入的密码
String password=s.nextLine().trim();
// 调用logincheck方法进行登录判断
boolean flag=loginCheck(username,password);
if(flag){
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
}
/**
* 用用户名和密码进行登录的方法
* @param username 用户名
* @param password 密码
* @return true-登录成功 false-登录失败
*/
public static boolean loginCheck(String username,String password){
String sql="select * from user where username='"+username+"' and password='"+password+"'";
Connection conn=null;
Statement st=null;
ResultSet rs=null;
try{
// 调用获取连接的静态方法getConnection()
// 建立连接
conn=JDBCUtils.getConnection();
// 创建SQL的执行器
st=conn.createStatement();
// 执行SQL语句
rs=st.executeQuery(sql);
// 对结果集进行操作
if(rs.next()){
// 查到了数据,登录成功
return true;
}else{
// 没有查到数据,登录失败
return false;
}
}catch (Exception e) {
e.printStackTrace();
}finally{
// 调用close(自己定义的)静态方法,关闭连接,释放资源
JDBCUtils.close(conn, st, rs);
}
return false;
}
}
3.运行代码:![](https://img-blog.csdnimg.cn/2d074e521f1646628677f8c140d42e91.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ZizWW91bmdlcg==,size_18,color_FFFFFF,t_70,g_se,x_16)
到目前为止,结果和预想的一样, 但是当我输入 张三' # 或者 张三' or ' 以下内容,神奇的现象发生了.
![](https://img-blog.csdnimg.cn/6d388c17d2114e329200a41e4f5bb8f5.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ZizWW91bmdlcg==,size_20,color_FFFFFF,t_70,g_se,x_16)
这就是SQL注入的现象, 为什么会出现这样的现象?
我们认为SQL语句应该是
"select * from user where username=' "+"张三"+" ' and password=' "+"123"+" ' ";
但实际情况是
"select * from user where username='张三' #' and password=' "+password+ " ' ";
#后面的语句被当作成了注释,所以不会再执行后面的语句了.
那我们怎么该避免这种情况呢?这时候就需要用到PreparedStatement对象。
PreparedStatement是Statement的子类,不同的是,PreparedStatement使用预编译机制,在创建PreparedStatement对象时就需要将sql语句传入,传入的过程中参数用?替代,这个过程会导致传入的sql被进行预编译,然后再调用PreparedStatement的setXXX将参数设置上去,由于sql语句已经经过了预编译,再传入特殊值也不会起作用了。
PreparedStatement优点:
可以防止sql注入攻击
采用预编译机制, 效率高
如果发送的sql语句主干部分相同, 主干部分只需要写一次, 每次发送的只是参数部分.
所以用PreparedStatement对象处理SQL注入
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class login {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.println("您好,请输入用户名:");
// 获取用户输入的用户名
String username=s.nextLine().trim();
System.out.println("请输入密码:");
// 获取用户输入的密码
String password=s.nextLine().trim();
// 调用logincheck1方法进行登录判断
boolean flag=loginCheck1(username,password);
if(flag){
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
}
//更新logincheck后的方法
public static boolean loginCheck1(String username,String password){
// ?作为占位符
String sql="select * from user where username=? and password=?";
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
try {
conn=JDBCUtils.getConnection();
ps=conn.prepareStatement(sql);
ps.setString(1, username);
ps.setString(2, password);
rs=ps.executeQuery();
return rs.next();
} catch (Exception e) {
e.printStackTrace();
}finally{
JDBCUtils.close(conn, ps, rs);
}
return false;
}
}
这样SQL注入问题就解决了!!!