【JDBC】注入攻击与PreparedStatement

何为注入攻击?让我们先看一个小例子,我们编写一段程序,根据用户指定的name值返回记录。

 
 
String sql  =   " select * from test where name=' "   +  name  +   " ' " ;
state 
=  conn.createStatement();
rs 
=  state.executeQuery(sql);
//  显示查询结果
while  (rs.next())  {
    System.out.println(rs.getInt(
1+ " " + rs.getString(2));
}

这里我们直接使用用户传递过来的name变量拼接了一条sql语句进行查询。在String name = "lingirl2"的时候程序会返回正确的结果。

上面的例子里,我们乐观的认为用户输入的都是正常的字符串,没有考虑到恶意攻击的情况,如果用户输入了这样一段内容:

String name = "xxx' or '1'='";

经过拼接得到的sql就变成了这样。

select * from test where name='xxx' or '1'='1'

好啦,这会搜索出所有满足name='xxx'或者满足'1'='1'条件的记录,结果变成搜索test库中所有的记录了。

当String name = "xxx' or '1'='";的时候,查询结果如下:

所谓sql注入攻击,是因为程序没有对用户输入进行校验,造成用户可以在输入中包含恶意代码篡改程序功能。上面的例子仅仅是造成数据泄密,更严重的用户还可能窃取最高管理权限,删除数据库中所有的数据。

为了解决这个问题,我们可以使用PreparedStatement,修改后的代码如下。


 
 
import  java.sql. * ;

public   class  Select3  {
    
public static void main(String[] args) throws Exception {
        String name 
= "xxx' or '1'='1";

        Connection conn 
= DbUtils.getConnection();
        PreparedStatement state 
= null;
        ResultSet rs 
= null;
        
try {
            String sql 
= "select * from test where name=?";
            state 
= conn.prepareStatement(sql);
            state.setString(
1, name);
            rs 
= state.executeQuery();
            
// 显示查询结果
            while (rs.next()) {
                System.out.println(rs.getInt(
1+ " " + rs.getString(2));
            }

        }
 catch(Exception ex) {
            ex.printStackTrace();
        }
 finally {
            
if (rs != null{
                rs.close();
            }

            
if (state != null{
                state.close();
            }

            DbUtils.close(conn);
        }

    }

}

通过如下几步将Statement改为PreparedStatement。

  1. sql语句修改为

    select * from test where name=?

    注意这个问号(?)就是我们需要传递参数的地方。

  2. 使用prepareStatement获得PreparedStatement变量。

    state = conn.prepareStatement(sql);

    与createStatement不同,创建的PreparedStatement的同时要传入sql语句,让PreparedStatement对sql语句进行预处理,以备后用。

  3. 传入name参数。

    state.setString(1, name);

    这里的参数“1”代表使用name替代sql中的第一个问号“?”,name中有什么特殊字符,PreparedStatement会帮助咱们自动转换。

  4. 最后执行查询,rs = state.executeQuery();因为创建PreparedStatement的时候就已经对sql进行了处理,这里直接执行查询就能得到结果。

看一下使用PreparedStatement查询String name = "xxx' or '1'='";的情况。

实际上,自己手工拼接sql非常容易出错,即便不担心注入攻击也应该尽量使用PreparedStatement,至少可以减小写错sql的机会。

最后放上一个使用PreparedStatement进行插入的例子,可以自己写一个不使用PreparedStatement的例子对比一下。


  
  
import  java.sql. * ;

public   class  Insert  {
    
public static void main(String[] args) throws Exception {
        
int id = 1;
        String name 
= "lingirl";

        Connection conn 
= DbUtils.getConnection();
        PreparedStatement state 
= null;
        
try {
            String sql 
= "insert into test(id,name) values(?,?)";
            state 
= conn.prepareStatement(sql);
            state.setInt(
1, id);
            state.setString(
2, name);

            state.executeUpdate();
        }
 catch(Exception ex) {
            ex.printStackTrace();
        }
 finally {
            
if (state != null{
                state.close();
            }

            DbUtils.close(conn);
        }

    }



}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值