热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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 {@Overrideprotected 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 表如下:

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

 1' OR '1'='1,也是可以登入成功的。

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


  • 漏洞原因

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


  • PreparedStament 化解 SQL 注入

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

代码修改为:

public class LoginServlet extends HttpServlet {@Overrideprotected 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 无法登入。

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


推荐阅读
author-avatar
123妖_精
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有