java sql 注入攻击_java学习笔记38(sql注入攻击及解决方法)

上一篇我们写了jdbc工具类:JDBCUtils ,在这里我们使用该工具类来连接数据库,

在之前我们使用 Statement接口下的executeQuery(sql)方法来执行搜索语句,但是这个接口并不安全,容易被注入攻击,注入攻击示例:

首先我们需要一个存放登录用户名密码的表:

useqy97;create tablelogin(

idint primary keyauto_increment,

snamevarchar(50),

pwdvarchar(50)

);insert into login values(1,'zhangsan','111'),

(2,'lisi','123');

然后我们写代码实现登陆:

packagecom.zs.Demo;importJDBCUtils.JDBCUtils;importjava.sql.Connection;importjava.sql.ResultSet;importjava.sql.SQLException;importjava.sql.Statement;importjava.util.Scanner;public classSQLZhuRu {public static voidmain(String[] args) {

Scanner sc=newScanner(System.in);

System.out.println("请输入用户名:");

String name=sc.nextLine();

System.out.println("请输入密码:");

String pwd=sc.nextLine();

login(name,pwd);

}private static voidlogin(String name, String pwd) {

Connection conn=JDBCUtils.getConnection();

String sql= "select * from login where sname='"+name+"'and pwd='"+pwd+"';";

System.out.println(sql);

Statement stat= null;

ResultSet rs=null;try{

stat=conn.createStatement();

rs=stat.executeQuery(sql);if(rs.next()) {

System.out.println("登陆成功,欢迎" + rs.getString("sname"));

}else{

System.out.println("登录失败!!");

}

}catch(SQLException e) {

e.printStackTrace();

}

JDBCUtils.close(conn,stat,rs);

}

}

运行结果如下:

ac8246b7ace2e192eda23474f5f1712e.png

输入账号密码,然后在数据库中搜索,搜索到数据则登录成功,否则登录失败:

ad7303242cd7f0e01e3dba5f6af715ad.png

可是,当我们这样输入时,也能登陆成功:

74bd61afdf7e245ec24392a38d9c50ba.png

从上面语句可以看出,执行的sql与语句是:select * from login where sname='lisi'and pwd='789 'or'1=1';

1=1是恒成立的,or 只要两边有一个为true 则为 true  ,所以登录成功,这是一个最简单的注入攻击,

解决方法:使用prepareStatement接口,以上一个例子为基础做修改

packagecom.zs.Demo;importJDBCUtils.JDBCUtils;importjava.sql.Connection;importjava.sql.PreparedStatement;importjava.sql.ResultSet;importjava.util.Scanner;public classPerpareStatementDemo {public static voidmain(String[] args) {

Scanner sc=newScanner(System.in);

System.out.println("请输入用户名:");

String name=sc.nextLine();

System.out.println("请输入密码:");

String pwd=sc.nextLine();try{

login(name,pwd);

}catch(Exception e) {

e.printStackTrace();

}

}//传递变量name pwd给方法

private static void login(String name, String pwd) throwsException {

Connection conn=JDBCUtils.getConnection();//设置?占位置,将查询的参数用?来替换

String sql="select * from login where sname=? and pwd=?";

PreparedStatement pre=conn.prepareStatement(sql);//setObject方法来设置占位的?的值

pre.setObject(1,name);//设置第一个?的值为变量name

pre.setObject(2,pwd);//设置第二个?的值为变量pwd

ResultSet rs =pre.executeQuery();if(rs.next()) {

System.out.println("登陆成功");

}else{

System.out.println("登录失败");

}

JDBCUtils.close(conn, pre, rs);

}

}

运行结果:

0aa8199be24796a6b59a50b7613b3287.png

可以看出,在不改变sql语句的情况下将?替换为变量的值,当注入攻击时:

e7267fda5fe93cc79c34dada070eb5ee.png

可以看出来这个接口更加安全,所以建议使用这个接口来实现增删改查;关于PrepareStatement接口:(官方文档)

PrepareStatement接口:

表示预编译的SQL语句的对象。

SQL语句已预编译并存储在PreparedStatement对象中。 然后可以使用该对象多次有效地执行此语句。

注意:setter方法( setShort , setString用于设置IN参数值必须指定与所定义的SQL类型的输入参数的兼容的类型,等等)。 例如,如果IN参数具有SQL类型INTEGER ,   则应使用方法setInt 。

使用PrepareStatemnet接口实现数据库的更新:

packagecom.zs.Demo;importJDBCUtils.JDBCUtils;importjava.sql.Connection;importjava.sql.PreparedStatement;public classPrepareStatementDemo2 {public static voidmain(String[] args) {

Connection conn=JDBCUtils.getConnection();

String sql="update login set sname = ? where id=?;";

PreparedStatement pst=null;try{

pst=conn.prepareStatement(sql);

pst.setObject(1, "dijia");

pst.setObject(2,1);

pst.executeUpdate();

}catch(Exception e) {

e.printStackTrace();

}finally{

JDBCUtils.close(conn, pst);

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值