【Java编程】JDBC注入攻击-Statement 与 PreparedStatement

在上一篇【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端測试结果:

User [id=2, username=jack, password=jack, gender=true, regtime=2014-05-14]

測试结果表明:通过一个有效的username和password,成功获取到了该用户的全部信息。

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中新增一个注入攻击測试,username输入:hack(随意字符串),password输入:' or '1'='1

	public void queryByUserInjectTest(){
		DBHelper.queryByUser("hack", "' or '1'='1");
	}

Java端測试结果:

User [id=1, username=andy, password=andy, gender=true, regtime=2014-05-13]
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端測试结果:

User [id=2, username=jack, password=jack, gender=true, regtime=2014-05-14]

測试结果表明:通过一个合法的username和password。得到了该用户的全部信息。

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,谢谢!

posted @ 2017-05-03 17:54  zhchoutai  阅读(287)  评论(0)    收藏  举报