在上一篇【Java编程】建立一个简单的JDBC连接-Drivers, Connection, Statement and PreparedStatement我们介绍了如何使用JDBC驱动建立一个简单的连接,并实现使用Statement和PreparedStatement进行数据库查询,本篇blog将接着上篇blog通过SQL注入攻击比较Statement和PreparedStatement。当然这两者还有很多其他方面的不同,在之后的blog中会继续更新。
【Statement查询】
1、在DBHelper.java中新增一个通过username和password查询user的方法。
public static void queryByUser(String username,String password) { Connection conn = DBConnection.getConnection(); Statement stmt = null; ResultSet rs = null; try { stmt = conn.createStatement(); rs = stmt.executeQuery("select * from user where username = ‘" + username+"‘ and password=‘"+password+"‘"); while (rs.next()) { User user = new User(); user.setId(rs.getInt("id")); user.setUsername(rs.getString("username")); user.setPassword(rs.getString("password")); user.setGender(rs.getBoolean("gender")); user.setRegtime(rs.getDate("regtime")); System.out.println(user.toString()); } } catch (SQLException e) { e.printStackTrace(); }finally { DBConnection.closeResultSet(rs); DBConnection.closeStatement(stmt); DBConnection.closeConnection(conn); } }2、在DBHelperTest.java中新增一个测试方法进行测试
public void queryByUserTest(){ DBHelper.queryByUser("jack", "jack"); }
Java端测试结果:
测试结果表明:通过一个有效的用户名和密码,成功获取到了该用户的所有信息。
3、 通过MySQL日志信息,跟踪查询sql语句。具体方法参考 MySQL如何跟踪sql语句。
打开mysql.log日志,跟踪查看最新的日志,如下所示:
140514 10:16:13 15 Query SET character_set_results = NULL 15 Query SHOW VARIABLES 15 Query SHOW WARNINGS 15 Query SHOW COLLATION 15 Query SET autocommit=1 15 Query select * from user where username = ‘jack‘ and password=‘jack‘ 15 Quit
日志信息表明:数据库端执行了正常的查询语句。
4、在DBHelperTest.java中新增一个注入攻击测试,用户名输入:hack(任意字符串),密码输入:‘ or ‘1‘=‘1
public void queryByUserInjectTest(){ DBHelper.queryByUser("hack", "‘ or ‘1‘=‘1"); }
Java端测试结果:
User [id=2, username=jack, password=jack, gender=true, regtime=2014-05-14]
User [id=3, username=rose, password=rose, gender=false, regtime=2014-05-13]
测试结果表明:通过注入攻击,一个非法的用户可以获取到user表中的所有用户信息,太可怕了!
5、通过MySQL日志信息,跟踪查询sql语句,分析数据端到底发生了什么事情。
140514 10:23:14 16 Connect root@localhost on db_bbs 16 Query SET NAMES latin1 16 Query SET character_set_results = NULL 16 Query SHOW VARIABLES 16 Query SHOW WARNINGS 16 Query SHOW COLLATION 16 Query SET autocommit=1 16 Query select * from user where username = ‘hack‘ and password=‘‘ or ‘1‘=‘1‘ 16 Quit数据库端执行了一条语句:
select * from user where username = ‘hack‘ and password=‘‘ or ‘1‘=‘1‘
因为where条件恒为真,相当于执行了:
select * from user
通过这条语句获取到了所有的用户信息。
【PreparedStatement查询】
1、在DBHelper.java中新增一个通过username和password查询user的方法。public static void queryPrepareByUser(String username,String password) { Connection conn = DBConnection.getConnection(); PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement("select * from user where username = ? and password = ?"); ps.setString(1,username);// 设置占位符参数 ps.setString(2, password); rs = ps.executeQuery(); while (rs.next()) { User user = new User(); user.setId(rs.getInt("id")); user.setUsername(rs.getString("username")); user.setPassword(rs.getString("password")); user.setGender(rs.getBoolean("gender")); user.setRegtime(rs.getDate("regtime")); System.out.println(user.toString()); } } catch (SQLException e) { e.printStackTrace(); } finally { DBConnection.closeResultSet(rs); DBConnection.closeStatement(ps); DBConnection.closeConnection(conn); } }2、在DBHelperTest.java中新增一个测试方法进行测试
public void queryByPreparedUserTest(){ DBHelper.queryPrepareByUser("jack", "jack"); }Java端测试结果:
测试结果表明:通过一个合法的用户名和密码,得到了该用户的所有信息。
3、 通过MySQL日志信息,跟踪查询sql语句。
140514 10:37:04 17 Connect root@localhost on db_bbs 17 Query SET NAMES latin1 17 Query SET character_set_results = NULL 17 Query SHOW VARIABLES 17 Query SHOW WARNINGS 17 Query SHOW COLLATION 17 Query SET autocommit=1 17 Prepare select * from user where username = ? and password = ? 17 Execute select * from user where username = ‘jack‘ and password = ‘jack‘ 17 Close stmt 17 Quit日志信息表明:数据库端首先执行了预编译,并执行了正常的查询语句。
4、在DBHelperTest.java中新增一个注入攻击测试:
public void queryByPreparedUserInjectTest(){ DBHelper.queryPrepareByUser("hack", "‘ or ‘1‘=‘1"); }
Java端测试结果:
没有打印出任何消息,即没有获取到用户的信息,难道注入攻击无效!
5、通过MySQL日志信息,跟踪查询sql语句,为什么注入攻击无效了?
140514 10:42:42 19 Query SET character_set_results = NULL 19 Query SHOW VARIABLES 19 Query SHOW WARNINGS 19 Query SHOW COLLATION 19 Query SET autocommit=1 19 Prepare select * from user where username = ? and password = ? 19 Execute select * from user where username = ‘hack‘ and password = ‘\‘ or \‘1\‘=\‘1‘ 19 Close stmt 19 Quit
原来是执行了:select * from user where username = ‘hack‘ and password = ‘\‘ or \‘1\‘=\‘1‘
【参考】
JDBC Statement vs PreparedStatement – SQL Injection Example(推荐)
JDBC为什么要使用PreparedStatement而不是Statement
【你可能感兴趣】
建立一个简单的JDBC连接-Drivers, Connection, Statement and PreparedStatement
转载请注明出处:http://blog.csdn.net/andie_guo/article/details/25775163,谢谢!
【Java编程】JDBC注入攻击-Statement 与 PreparedStatement,布布扣,bubuko.com