安全攻防技能 30 讲
何为舟
前微博安全研发负责人
34681 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 41 讲
开篇词 (1讲)
安全攻防技能 30 讲
15
15
1.0x
00:00/00:00
登录|注册

07 | SQL注入:明明设置了强密码,为什么还会被别人登录?

了解UNION概念
避免SQL语句中出现字符串拼接的操作
对所有输入进行验证或过滤操作
将解析SQL的过程由数据库驱动转移到数据库本身
合理使用可避免99.99%的SQL注入问题
示例:1;DROP TABLE Users
利用分号分割SQL语句
示例:输入" or ""="
获取除Username之外的其他字段
验证输入
使用存储过程
使用PreparedStatement
消耗资源
窃取数据
任意篡改数据
绕过验证
执行任意语句
修改WHERE语句
黑客通过恶意输入参数篡改SQL语句
用户登录时执行SQL语句
用户信息存储在数据库中
思考题
防护方法
攻击后果
攻击方式
产生原因
SQL注入攻击

该思维导图由 AI 生成,仅供参考

你好,我是何为舟。
在上一讲中,我们介绍了 XSS 攻击。今天,我们来介绍另外一种常见的 Web 攻击:SQL 注入。
在讲正文之前,让我们先来看一个案例。某天,当你在查看应用的管理后台时,发现有很多异常的操作。接着,你很快反应过来了,这应该是黑客成功登录了管理员账户。于是,你立刻找到管理员,责问他是不是设置了弱密码。管理员很无辜地表示,自己的密码非常复杂,不可能泄露,但是为了安全起见,他还是立即修改了当前的密码。奇怪的是,第二天,黑客还是能够继续登录管理员账号。问题来了,黑客究竟是怎么做到的呢?你觉得这里面的问题究竟出在哪里呢?你可以先自己思考一下,然后跟着我开始今天的学习!

SQL 注入攻击是如何产生的?

在上一讲中,我们讲了,XSS 是黑客通过篡改 HTML 代码,来插入并执行恶意脚本的一种攻击。其实,SQL 注入和 XSS 攻击很类似,都是黑客通过篡改代码逻辑发起的攻击。那么,不同的点是什么?SQL 注入到底是什么呢?
通常来说,我们会将应用的用户信息存储在数据库中。每次用户登录时,都会执行一个相应的 SQL 语句。这时,黑客会通过构造一些恶意的输入参数,在应用拼接 SQL 语句的时候,去篡改正常的 SQL 语意,从而执行黑客所控制的 SQL 查询功能。这个过程,就相当于黑客“注入”了一段 SQL 代码到应用中。这就是我们常说的 SQL 注入
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文详细介绍了SQL注入攻击的原理、影响和防护方法。通过案例和示例,阐述了SQL注入攻击的产生方式,包括修改WHERE语句和执行任意语句两种主要方式。进一步指出,SQL注入攻击可能导致绕过验证、数据篡改、数据窃取和资源消耗等严重后果。文章提出了三种常见的防护方法:使用PreparedStatement、使用存储过程和验证输入。其中,使用PreparedStatement能够避免99.99%的SQL注入问题,通过将SQL语句的解析和执行过程分开,实现防护。另外,使用存储过程和验证输入也是有效的防护手段。总结指出,正确使用PreparedStatement方法或存储过程,尽量避免字符串拼接操作,以及对用户输入进行验证和过滤,是避免SQL注入的关键。文章还提出了思考题,引发读者思考和讨论。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《安全攻防技能 30 讲》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(21)

  • 最新
  • 精选
  • 豆豆
    之前只是知道些简单的 SQL 注入方式以及防范措施,今天文末的盲注确实涨了知识,关于思考题自己做了如下的练习。 首先盲注应该也是通过 web 端的输入来实现黑客的入侵目的的,那么黑客就可以通过观察页面的反应来动态修改自己的注入参数。比如一些提交输入框,当我们提交了参数之后页面反应正常那么就说明我们的猜测是正确的,否则继续猜。 我们都知道 MySQL 内部有一个 information_schema 的库,里面都是数据裤的元信息,那么我们就可以利用这个库进行猜测,通过观察页面的反应来验证自己的猜测是否正确。 第一步我们要知道数据的名字,那么就先猜测其长度。以下我们会用到 DATABASE(), LENGTH(), SUBSTRING(), ASCII() 四个内置函数。 1. 确定数据库长度 SELECT name FROM user WHERE id = 1 AND (SELECT LENGTH(DATABASE()) = 4); 得到数据库长度之后猜测数据库名字的每个字母。 2. 确定数据库名字 通过 ASCII 码方式 SELECT name FROM user WHERE id = 1 AND (SELECT ASCII(SUBSTRING(DATABASE(), 1, 1)) < 128); 根据 ASCII 码猜测是可以使用二分法来猜测。假设的到的结果是 test。 得到数据库名字之后,猜测 user 表有多少个列。 3. 获取该表有多少列 SELECT name FROM user WHERE id = 1 AND ((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE table_name = 'user' AND TABLE_SCHEMA = 'test') = 3); 获取到列的多少列之后,就可以获取到每一列的长度了。 4. 获取列长 SELECT name FROM user WHERE id = 1 AND ((SELECT LENGTH(column_name) FROM information_schema.COLUMNS WHERE table_name = 'user' AND TABLE_SCHEMA = 'test' LIMIT 0, 1) = 2); 最后,获取每一列的具体值。 5. 获取列名,同样是使用 ASCII 码方式 SELECT name FROM user WHERE id = 1 AND ((SELECT ASCII(SUBSTRING(column_name, 1, 1)) FROM information_schema.COLUMNS WHERE table_name = 'user' AND TABLE_SCHEMA = 'test' LIMIT 0, 1) < 120) 为了故事的顺利发展这里我假设我们已知表名 user,但是我们可以根据同样的逻辑从 information_schema.TABLES 表中获取 test 库的所有表信息。 最后,我感觉这个方式有点傻啊,因为它依赖一些很特定的条件,比如后端没有做 SQL 注入的防护,而且还必须结合前端页面的反应。

    作者回复: 赞,是这么个原理。

    2019-12-23
    46
  • 小晏子
    研究了下盲注的文章,长见识了,以前只是大概知道sql注入,知道最简单的方式,盲注这种方法还是第一次接触,针对这个思考题,可以按如下方式获取其他字段,思路如下,可以写脚本实现,还有前提是能够进行盲注, 1. 先判断字段的第一个字符是否在a-z中,如下所示, select Username from Users where UserId = 1 and 1 = (select 1 from information_schema.columns WHERE table_name='Users’ and COLUMN_NAME REGEXP '^[a-z]') 如果结果显示Username那就说明字段的第一个字符在a到z中, 2. 使用二分查找法在a到z之间查找第一个字符,如下语句, select Username from Users where UserId = 1 and 1 = (select 1 from information_schema.columns WHERE table_name='Users’ and COLUMN_NAME REGEXP '^a[a-z]') 如果能显示Username,那么就说明a是第一个字符,再依次去查第二个字符,反之,换一个字符再试。 3. 以此类推,可以找到所有的字段名。 顺便说下,字段名中可能包含其他字符,如 _ 等,可以在正则表达式中同样去匹配。

    作者回复: 赞~

    2019-12-23
    8
  • sober
    希望老师能抽出一节讲讲登录实战,想真正了解一下整个登录如何应用加密,谢谢老师了

    作者回复: 这块在前面的加密和认证应该有涉及,还有哪些问题,可以具体留言沟通一下。

    2019-12-24
    2
  • 小老鼠
    现在SQL注入不常见了吧,现在的开发框架都可避免SQL注入了吧。比如基于python的Django。

    作者回复: 如果使用了orm的话,确实不会出现。但如果还是自己写sql的话,其实还是很普遍的。

    2019-12-31
    2
    1
  • Gamer777
    通过使用 PreparedStatement,将 SQL 语句的解析和实际执行过程分开,只在执行的过程中代入用户的操作。分开执行还是无法防御SQL注入吗,不然为什么底层还是会对一些特殊符号进行转义操作?

    作者回复: 可以防御注入。底层进行转义,本质上就是preparedstatement帮你采取的防御措施,而不需要你去操心转义啥的。

    2020-07-18
  • HE明伟
    老师,现在的spring boot这些框架都能预防sql注入了吧

    作者回复: 正确使用的话,就可以

    2020-07-09
  • felix
    如果是string,还是解决不了第一个password或的情况?

    作者回复: 如果是字符串拼接然后直接执行sql,那就会被注入。

    2020-01-13
  • 律飛
    作为编程小白而言,学习难度有点大哦🙄。多看了好几篇盲注的文章,仍然是晕头转向的。豆豆已经提供了很好的答案。不过我还是来说说我的理解,不足之处请老师批评指正。 盲注其实就是结合SQL最基本的两种注入方式,不断去猜测并验证数据库可能的信息,最终获得答案的过程。这需要注入者简单的基础和丰富的经验,以及长时间频繁地跟数据库交互。 对于这种攻击,开发者采用PreparedStatment,存储过程,验证输入等方法就可以防范攻击。 请教老师:对于输入内容验证是不是还可以通过长度进行控制?对于盲注是不是可以通过单位时间内某个id跟数据库连接次数进行限制和预警?如果想动手试验,如何避免触碰红线?

    作者回复: 1、可以,就是有点弱。如果你限制只能一个字符的话,可能还行。 2、可以 3、自己搭环境。网上有开源的渗透测试环境,比如WebGoat,可以自己搭一个玩。

    2020-01-02
  • 小老鼠
    可介绍下sqlmap吗?

    作者回复: sqlmap是自动化进行sql注入的工具,这个专栏注重甲方安全防御,所以攻击只介绍原理,不会过多去涉及攻击的各种细节。这方面感兴趣的话,可以自学一下,有问题欢迎留言沟通。

    2019-12-31
  • Zhen
    了解了一下盲注,比较有意思,根据你SQL注入的攻击语句返回TRUE或者FALSE,可被用来一点点猜测获取数据库schema。 比如:如果 http://newspaper.com/items.php?id=2 and 1=2   返回FALSE;http://newspaper.com/items.php?id=2 and 1=1 返回正确,就说明后面输入的语句被服务器执行了   而且存在一个数字型的注入;那我们现在就可以开始盲注,判断它目前使用的数据库、版本、一点点猜测数据库内容。 另外有个很初级的问题想请教一下,SQL注入是不是所有SQL数据库固有的问题?为什么数据库本身不能自我完善做到输入参数的过滤和保护,而是要Java应用程序来通过PreparedStatement来做?

    作者回复: 数据库的任务就是执行SQL,在SQL注入的过程中,JAVA提交给数据库的,就是一条完整的SQL语句。因此,从数据库的角度,是没有任何问题的。

    2019-12-23
收起评论
显示
设置
留言
21
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部