SQL 注入攻击介绍与测试案例

博主声明:

转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主 威威喵 原创,请多支持与指教。

本文首发于此   博主:威威喵  |  博客主页:https://blog.csdn.net/smile_running

  • SQL注入攻击

    SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令,从而利用系统的 SQL 引擎完成恶意行为的做法 。   

    SQL注入攻击,指对数据库进行攻击的手段之一。例如:在表单提交时候,需要操作数据库去匹配用户信息时,在 sql 语句中注入一些代码,去获取数据库信息或权限。接着,我们来看看在SQL注入代码,成功入侵数据库的案例。

    本案例代码来自上篇:初探Servlet,HTML + JDBC + MySQL的一个小案例

  • Statement :罪魁祸首

    Statement 是 Jdbc 提供的一个可以操作数据库的方法,通常用于增、删、改、查;用它的 statement.executeQuery(sql) 方法可以执行数据库语句。

    案例关键代码如下:

public class LoginServlet extends HttpServlet {

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.setCharacterEncoding("utf-8");
		Connection conn = null;
		Statement statement = null;
		ResultSet result = null;
		PrintWriter out = resp.getWriter();

		String user = req.getParameter("user");
		String pwd = req.getParameter("pwd");
		System.out.println("请求:user:" + user);
		System.out.println("请求:pwd:" + pwd);

		try {
			conn = JdbcUtils.getConnection();
			statement = conn.createStatement();
			String sql = "SELECT * FROM user WHERE(user_name='" + user + "' AND password='" + pwd + "')";
			System.out.println(sql);
			result = statement.executeQuery(sql);
		
			//result 返回 true 说明匹配成功
			if (result.next()) {
				out.println("user,login succeed");
			} else {
				out.println("login failed");
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtils.release(statement, conn, result);
		}
	}
}

    如上代码中的 sql 语句: SELECT * FROM user WHERE(user_name='" + user + "' AND password='" + pwd + "'),看似没有任何问题,但配合着 Statement 就会出现漏洞了。接着我们来测试 SQL 注入。

  • 测试 SQL 注入攻击

    我的数据库有一张 user 表如下:

SQL 注入攻击介绍与测试案例_第1张图片

    我们使用表中的任何 user_name 和 password 都是可以登入的。接着,是用注入代码的方式: user 和 密码 都为

 1' OR '1'='1,也是可以登入成功的。SQL 注入攻击介绍与测试案例_第2张图片

SQL 注入攻击介绍与测试案例_第3张图片

    sql 语句变成如上图控制台打印出来的那样,我们拿到数据库软件中跑一下,也是可以查出来。后面的 ‘1’ = ‘1’ 为真,这句 sql 语句其实变成了 SELECT * FROM user ,结果也就是查询出 user 所有数据信息。

SQL 注入攻击介绍与测试案例_第4张图片

  • 漏洞原因

    出现这种情况的原因是,每次在请求登入的时候时, Statement 在执行 sql 语句时都会把表单提交来的 用户名 和 密码 都重新拼接到 sql 语句中,然后在执行。这样会导致 sql 语句结构发生改变,攻击者利用这种方式攻击数据库就称为 SQL注入攻击。

  • PreparedStament 化解 SQL 注入

    PreparedStament 是 Statement 的子接口,它最大特点就是预处理 sql 语句。它在实例化时,必须传入 sql 语句,这与Statement 就有所区别。sql 语句中使用占位符 ? 来代替未知参数值,继而通过 preparedStatement.setXXX() 方法添加进 sql 语句中,这样就不会改变 sql 的结构,就能防止 SQL 注入攻击了。

代码修改为:

public class LoginServlet extends HttpServlet {

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.setCharacterEncoding("utf-8");
		Connection conn = null;
		PreparedStatement preparedStatement = null;
		ResultSet result = null;
		PrintWriter out = resp.getWriter();

		String user = req.getParameter("user");
		String pwd = req.getParameter("pwd");
		System.out.println("请求:user:" + user);
		System.out.println("请求:pwd:" + pwd);

		try {
			conn = JdbcUtils.getConnection();
			String sql = "SELECT * FROM user WHERE(user_name=? AND password=?)";
			preparedStatement = conn.prepareStatement(sql);
			System.out.println(sql);
			preparedStatement.setString(1, user);
			preparedStatement.setString(2, pwd);
			result = preparedStatement.executeQuery();
		
			//result 返回 true 说明匹配成功
			if (result.next()) {
				out.println("user,login succeed");
			} else {
				out.println("login failed");
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtils.release(preparedStatement, conn, result);
		}
	}
}

    测试结果,使用 1' OR '1'='1 无法登入。

SQL 注入攻击介绍与测试案例_第5张图片

    所以,在日常开发中一般都使用 PreparedStatement ,它不仅可以防止 SQL 注入,同时能够预编译 sql  语句,效率更佳。

你可能感兴趣的:(#,JavaEE,Java)