返回顶端

SQL注入问题

SQL注入问题

一、什么是SQL注入

SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。——百度百科

二、举例:登录操作

正常的登录操作可以验证用户名和密码是否和数据库中的一致,但SQL注入却可以通过恶意输入使所有用户的用户名和密码等信息全部泄露,原理见后文。

1. 首先,在数据库中创建一个用户表

id username password
1 zs 111111
2 ls 222222
3 zzz 333333

2. 登录验证程序

连接数据库,并验证用户名和密码是否输入正确。

public static void login(String username,String password){
    Connection conn = null;
    Statement st = null;
    ResultSet rs = null;

    try {
        conn = JdbcUtils.getConnection();	//连接数据库
        st = conn.createStatement();
        String sql = "select * from `usersinfo` where `username`='"+username+"' and password='"+password+"'";//验证用户名和密码
        rs = st.executeQuery(sql);
        while (rs.next()){
            System.out.println("id="+rs.getInt("id"));
            System.out.println("username="+rs.getString("username"));
            System.out.println("password="+rs.getString("password"));
        }
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    } finally {
        JdbcUtils.release(conn,st,rs);
    }
}

3. 常规登录操作

public static void main(String[] args) {
    login("zs","111111");
}

结果

image-20210505154823101

查询出了用户名为"zs"密码为"111111"的用户,即登录成功。

4. SQL注入

public static void main(String[] args) {
    login("'or'1=1","'or'1=1");
}

结果

image-20210505155034529

查询出了所有用户的用户名和密码,即造成信息泄露。

5. 原理

在登录验证程序中,我们需要的一条SQL语句为

select * from `usersinfo` where `username` = 'xxxx' and `password` = 'xxxxx';

因此在java程序中用字符串拼接的写法为

String sql = "select * from `usersinfo` where `username`='"+username+"' and password='"+password+"'";

在SQL注入时,输入的username为 'or'1=1,password为 'or'1=1;

把恶意输入的username和password拼接入java字符串中,则出现

select * from `usersinfo` where `username` = ''or'1=1' and `password` = ''or'1=1';

执行这条SQL语句时,无论username和password是什么,都满足后面的1=1,因此可以匹配所有的数据,造成数据泄露!

三、使用PreparedStatement对象预防SQL注入

1. 用法

修改上述登录程序代码为

public static void login(String username,String password){
    Connection conn = null;
    PreparedStatement st = null;	//声明为PreparedStatement对象
    ResultSet rs = null;

    try {
        conn = JdbcUtils.getConnection();

        String sql = "select * from `usersinfo` where `username` = ? and `password` = ?";	//变量用问号替代
        st = conn.prepareStatement(sql);	//预编译SQL
        st.setString(1,username);			//使用set设置上述问号变量的实际值,第一个参数为第几个问号,第二个参数为要设置的值
        st.setString(2,password);
        rs = st.executeQuery();				//执行SQL,返回结果集
        while (rs.next()){
            System.out.println(rs.getInt("id"));
            System.out.println(rs.getString("username"));
            System.out.println(rs.getString("password"));
        }
    } catch (Exception throwables) {
        throwables.printStackTrace();
    } finally {				//释放资源
        JdbcUtils.release(conn,st,rs);
    }
}

2. SQL注入测试

public static void main(String[] args) {
    login("''or 1=1","''or 1=1");	//此例SQL注入写法与上例不同,注意观察
}

结果

无法查询到任何数据。

3. 原理

PreparedStatement对象把用户非法输入的单引号用\反斜杠进行了转义处理,在实现PreparedStatement接口的实现类中的setString(int parameterIndex, String x)函数中做了一些处理,把单引号做了转义(只要用户输入的字符串中有单引号,那数据库产商的setString()这个函数,就会把单引号做转义)。

posted @ 2021-05-06 15:23  EEEEEEEric  阅读(133)  评论(0)    收藏  举报