资讯动态

安全攻防六:SQL注入,明明设置了强密码,为什么还会被别人登录

发布时间:2026/8/23 13:51:09 来源:尧图企业网站定制
安全攻防六SQL注入明明设置了强密码为什么还会被别人登录在正文之前让我们先来看一个案例。某天当你在查看应用的管理后台时发现有很多异常的操作。接着你很快反应过来了这应该是黑客成功登录了管理员账户。于是你立刻找到管理员责问他是不是设置了弱密码。管理员很无辜地表示自己的密码非常复杂不可能泄漏但是为了安全起见他还是立即修改了当前的密码。奇怪的是第二天黑客还是能够继续登录管理员账号。问题来了黑客究竟是怎么做到的呢你觉得这里面的问题究竟出在哪里呢SQL 注入攻击是如何产生的在上一文中我们讲了XSS 是黑客通过篡改 HTML 代码来插入并执行恶意脚本的一种攻击。其实SQL 注入和 XSS 攻击很类似都是黑客通过篡改代码逻辑发起的攻击。那么不同的点是什么SQL 注入到底是什么呢通常来说我们会将应用的用户信息存储在数据库中。每次用户登录时都会执行一个相应的 SQL 语句。这时黑客会通过构造一些恶意的输入参数在应用拼接 SQL 语句的时候去篡改正常的 SQL 语意从而执行黑客所控制的 SQL 查询功能。这个过程就相当于黑客“注入”了一段 SQL 代码到应用中。这就是我们常说的 SQL 注入。这么说可能还是有点理论不够具体。接下来我就以几个简单而又经典的示例来给你介绍两种主要的 SQL 注入方式。修改 WHERE 语句我们先来看一个例子。现在有一个简单的登录页面需要用户输入 Username 和 Password 这两个变量来完成登录。具体的 Web 后台代码如下所示uName getRequestString(username); uPass getRequestString(password); sql SELECT * FROM Users WHERE Username uName AND Password uPass 当用户提交一个表单假设 Username 为 adminPassword 为 123456时Web 将执行下面这行代码SELECT * FROM Users WHERE Username admin AND Password 123456用户名密码如果正确的话这句 SQL 就能够返回对应的用户信息如果错误的话不会返回任何信息。因此只要返回的行数≥1就说明验证通过用户可以成功登录。所以当用户正常地输入自己的用户名和密码时自然就可以成功登录应用。那黑客想要在不知道密码的情况下登录应用他又会输入什么呢他会输入 or “”。这时应用的数据库就会执行下面这行代码SELECT * FROM Users WHERE Username AND Password or 我们可以看到WHERE 语句后面的判断是通过 or 进行拼接的其中“”“的结果是 true。那么当有一个 or 是 true 的时候最终结果就一定是 true 了。因此这个 WHERE 语句是恒为真的所以数据库将返回全部的数据。这样一来我们就能解答文章开头的问题了也就是说黑客只需要在登录页面中输入 or “””就可以在不知道密码的情况下成功登录后台了。而这也就是所谓的“万能密码”。而这个“万能密码”其实就是通过修改 WHERE 语句改变数据库的返回结果实现无密码登录。执行任意语句大部分的数据库都支持多语句执行。因此黑客除了修改原本的 WHERE 语句之外也可以在原语句的后面插入额外的 SQL 语句来实现任意的增删改查操作。在实际工作中MySQL 是最常用的数据库我们就以它为例来介绍一下任意语句是如何执行的。在 MySQL 中实现任意语句执行最简单的方法就是利用分号将原本的 SQL 语句进行分割。这样我们就可以一次执行多个语句了。比如下面这个语句在执行的时候会先插入一个行然后再返回 Users 表中全部的数据。INSERT INTO Users (Username, Password) VALUES(test,000000); SELECT * FROM Users;接下来我们来看一个具体的例子。在用户完成登录后应用通常会通过 userId 来获取对应的用户信息。其 Web 后台的代码如下所示uid getRequestString(userId); sql SELECT * FROM Users WHERE UserId uid;在这种情况下黑客只要在传入的 userId 参数中加入一个分号就可以执行任意的 SQL 语句了。比如黑客想“删库跑路”的话就令 userId 为 1;DROP TABLE Users那么后台实际执行的 SQL 就会变成下面这行代码而数据库中所有的用户信息就都会被删除。SELECT * FROM Users WHERE UserId 1DROP TABLE UsersSQL 注入的“姿势”还有很多比如没有回显的盲注、基于 INSERT 语句的注入等等它们的原理都是一样的都是通过更改 SQL 的语义来执行黑客设定的 SQL 语句。通过 SQL 注入攻击黑客能做什么通过上面对 SQL 注入的简单介绍我们已经知道SQL 注入会令 Web 后台执行非常规的 SQL 语句从而导致各种各样的问题。那么通过 SQL 注入攻击黑客究竟能够干些什么呢1.绕过验证在上面的内容中我们已经介绍过 or “” 作为万能密码可以让黑客在不知道密码的情况下通过登录认证。因此SQL 注入最直接的利用方式就是绕过验证也就相当于身份认证被破解了。2.任意篡改数据除了绕过验证我们在任意语句执行的部分中讲到SQL 注入漏洞导致黑客可以执行任意的 SQL 语句。因此通过插入 DML 类的 SQL 语句INSERT、UPDATE、DELETE、TRUNCATE、DROP 等黑客就可以对表数据甚至表结构进行更改这样数据的完整性就会受到损害。比如上面例子中黑客通过插入 DROP TABLE Users删除数据库中全部的用户。3.窃取数据在 XSS 漏洞中黑客可以通过窃取 Cookie 和“钓鱼”获得用户的隐私数据。那么在 SQL 注入中黑客会怎么来获取这些隐私数据呢在各类安全事件中我们经常听到“拖库”这个词。所谓“拖库”就是指黑客通过类似 SQL 注入的手段获取到数据库中的全部数据如用户名、密码、手机号等隐私数据。最简单的黑客利用 UNION 关键词SELECT * FROM Users WHERE UserId 1 UNION SELECT * FROM Users将 SQL 语句拼接成这行代码之后就可以直接获取全部的用户信息了。4.消耗资源除了获取数据之外影响服务可用性也是黑客的目标之一。SQL 注入破坏可用性十分简单可以通过完全消耗服务器的资源来实现。比如在 Web 后台中黑客可以利用 WHILE 打造死循环操作或者定义存储过程触发一个无限迭代等等。在这些情况下数据库服务器因为 CPU 被迅速打满持续 100%而无法及时响应其他请求。总结来说通过 SQL 注入攻击黑客可以绕过验证登录后台非法篡改数据库中的数据还能执行任意的 SQL 语句盗取用户的隐私数据影响公司业务等等。所以我认为SQL 注入相当于让黑客直接和服务端的数据库进行了交互。正如我们一直所说的应用的本质是数据黑客控制了数据库也就相当于控制了整个应用。如何进行 SQL 注入防护在认识到 SQL 注入的危害之后我们知道一个简单的 SQL 查询逻辑能够带来巨大的安全隐患。因此我们应该做到在开发过程中就避免出现 SQL 注入漏洞。那具体应该怎么做呢 3 种常见的防护方法它们分别是使用 PreparedStatement、使用存储过程和验证输入。1.使用 PreparedStatement通过合理地使用 PreparedStatement我们就能够避免 99.99% 的 SQL 注入问题。你肯定很好奇我为什么会这么说。接下来让我们一起看一下它的实现过程。当数据库在处理一个 SQL 命令的时候大致可以分为两个步骤将 SQL 语句解析成数据库可使用的指令集。我们在使用 EXPLAIN 关键字分析 SQL 语句就是干的这个事情将变量代入指令集开始实际执行。之所以在批量处理 SQL 的时候能够提升性能就是因为这样做避免了重复解析 SQL 的过程。那么 PreparedStatement 为什么能够避免 SQL 注入的问题呢这是因为SQL 注入是在解析的过程中生效的用户的输入会影响 SQL 解析的结果。因此我们可以通过使用 PreparedStatement将 SQL 语句的解析和实际执行过程分开只在执行的过程中代入用户的操作。这样一来无论黑客提交的参数怎么变化数据库都不会去执行额外的逻辑也就避免了 SQL 注入的发生。在 Java 中我们可以通过执行下面的代码将解析和执行分开String sql SELECT * FROM Users WHERE UserId ?; PreparedStatement statement connection.prepareStatement(sql); statement.setInt(1, userId); ResultSet results statement.executeQuery();为了实现相似的效果在 PHP 中我们可以使用 PDOPHP Data Objects在 C# 中我们可以使用 OleDbCommand 等等。这里有一点需要你注意前面我们说了通过合理地使用 PreparedStatement 就能解决 99.99% 的 SQL 注入问题那到底怎么做才算“合理地”使用呢PreparedStatement 为 SQL 语句的解析和执行提供了不同的“方法”你需要分开来调用。但是如果你在使用 PreparedStatement 的时候还是通过字符串拼接来构造 SQL 语句那仍然是将解析和执行放在了一块也就不会产生相应的防护效果了。我这里给你展示了一个错误案例你可以和上面的代码进行对比。String sql SELECT * FROM Users WHERE UserId userId; PreparedStatement statement connection.prepareStatement(sql); ResultSet results statement.executeQuery();2.使用存储过程实际上它的原理和使用 PreparedStatement 类似都是通过将 SQL 语句的解析和执行过程分开来实现防护。区别在于存储过程防注入是将解析 SQL 的过程由数据库驱动转移到了数据库本身。还是上述的例子使用存储过程我们可以这样来实现delimiter $$ #将语句的结束符号从分号;临时改为两个$$(可以是自定义) CREATE PROCEDURE select_user(IN p_id INTEGER) BEGIN SELECT * FROM Users WHERE UserId p_id; END$$ delimiter; #将语句的结束符号恢复为分号 call select_user(1);3.验证输入防护的核心原则是一切用户输入皆不可信。因此SQL 注入的防护手段和 XSS 其实也是相通的主要的不同在于1.SQL 注入的攻击发生在输入的时候因此我们只能在输入的时候去进行防护和验证2.大部分数据库不提供针对 SQL 的编码因为那会改变原有的语意所以 SQL 注入没有编码的保护方案。因此对所有输入进行验证或者过滤操作能够很大程度上避免 SQL 注入的出现。比如在通过 userId 获取 Users 相关信息的示例中我们可以确认 userId 必然是一个整数。因此我们只需要对 userId 参数进行一个整型转化比如Java 中的 Integer.parseIntPHP 的 intval就可以实现防护了。当然部分场景下用户输入的参数会比较复杂。我们以用户发出的评论为例其内容完全由用户定义应用无法预判它的格式。这种情况下应用只能通过对部分关键字符进行过滤来避免 SQL 注入的发生。比如在 MySQL 中需要注意的关键词有 % ’ / /_。这里我简单地总结一下在实际使用这些防护方法时的注意点。对于验证输入来说尤其是在复杂场景下的验证输入措施其防护效果是最弱的。因此避免 SQL 注入的防护方法首要选择仍然是 PreparedStatement 或者存储过程。总结SQL 注入就是黑客通过相关漏洞篡改 SQL 语句的攻击。通过 SQL 注入黑客既可以影响正常的 SQL 执行结果从而绕过验证也可以执行额外的 SQL 语句对数据的机密性、完整性和可用性都产生影响。为了避免 SQL 注入的出现我们需要正确地使用 PreparedStatement 方法或者存储过程尽量避免在 SQL 语句中出现字符串拼接的操作。除此之外SQL 注入的防护也可以和 XSS 一样对用户的输入进行验证、检测并过滤 SQL 中的关键词从而避免原有语句被篡改。脑图送给大家《网络安全从零到精通全套学习大礼包》96节从入门到精通的全套视频教程免费领取如果你也想通过学网络安全技术去帮助就业和转行我可以把我自己亲自录制的96节 从零基础到精通的视频教程以及配套学习资料无偿分享给你。网络安全学习路线图想要学习 网络安全作为新手一定要先按照路线图学习方向不对努力白费。对于从来没有接触过网络安全的同学我帮大家准备了从零基础到精通学习成长路线图以及学习规划。可以说是最科学最系统的学习路线大家跟着这个路线图学习准没错。配套实战项目/源码所有视频教程所涉及的实战项目和项目源码学习电子书籍学习网络安全必看的书籍和文章的PDF市面上网络安全书籍确实太多了这些是我精选出来的面试真题/经验以上资料如何领取6034045b97ae8ac36b2a650.png)以上资料如何领取文章来自网上侵权请联系博主

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价