Web安全学院
Web安全学院
  • 首页
  • 译序
  • 学习路线
  • 前篇
    • Web应用程序安全测试
    • 动态应用程序安全测试(DAST)
    • 带外应用程序安全测试(OAST)
  • 服务器端主题
    • SQL注入
      • SQL注入
      • SQL注入UNION攻击
      • 在SQL注入攻击中检索数据库
      • SQL盲注
      • SQL注入速查表
    • 认证
      • 认证漏洞
      • 基于密码登录中的漏洞
      • 多因素认证中的漏洞
      • 其他认证机制中的漏洞
      • 如何保护你的认证机制
    • 目录遍历
      • 目录遍历
    • 命令注入
      • OS命令注入
    • 业务逻辑漏洞
      • 业务逻辑漏洞
      • 业务逻辑漏洞示例
    • 信息泄露
      • 信息泄露漏洞
      • 如何发现并利用信息泄露漏洞
    • 访问控制
      • 访问控制漏洞与权限提升
      • 不安全的直接对象引用(IDOR)
      • 访问控制安全模型
    • 文件上传漏洞
      • 文件上传漏洞
    • 条件竞争
      • 条件竞争
    • 服务器端请求伪造(SSRF)
      • 服务器端请求伪造(SSRF)
      • 盲SSRF漏洞
    • XXE注入
      • XML外部实体(XXE)注入
      • XML实体
      • 发现并利用盲XXE漏洞
  • 客户端主题
    • 跨站脚本(XSS)
      • 跨站脚本
      • 反射型XSS
      • 存储型XSS
      • 基于DOM的XSS
      • XSS上下文
        • 跨站脚本上下文
        • 客户端模版注入
      • 利用跨站脚本漏洞
      • 内容安全策略
      • 悬空标记注入
      • 如何防范XSS漏洞
      • 跨站脚本(XSS)速查表
    • 跨站请求伪造(CSRF)
      • 跨站请求伪造(CSRF)
      • XSS与CSRF
      • 绕过CSRF令牌验证
      • 绕过SameSite Cookie限制
      • 绕过基于Referer的CSRF防御
      • 如何防范CSRF漏洞
    • 跨域资源共享(CORS)
      • 跨域资源共享(CORS)
      • 同源策略(SOP)
      • CORS和Access-Control-Allow-Origin响应标头
    • 点击劫持
      • 点击劫持(UI伪装)
    • 基于DOM的漏洞
      • 基于DOM的漏洞
      • 控制Web消息源
      • 基于DOM的开放重定向
      • 基于DOM的Cookie操纵
      • 基于DOM的JavaScript注入
      • 基于DOM的document-domain操纵
      • 基于DOM的WebSocket URL投毒
      • 基于DOM的链接操纵
      • Web消息操纵
      • 基于DOM的Ajax请求标头操纵
      • 基于DOM的本地文件路径操纵
      • 基于DOM的客户端SQL注入
      • 基于DOM的HTML5 Storage操纵
      • 基于DOM的客户端XPath注入
      • 基于DOM的客户端JSON注入
      • DOM-data操纵
      • 基于DOM的拒绝服务
      • DOM破坏
    • WebSocket
      • 测试WebSocket安全漏洞
      • 什么是WebSocket?
      • 跨站WebSocket劫持
  • 进阶主题
    • 不安全的反序列化
      • 不安全的反序列化
      • 利用不安全的反序列化漏洞
    • 测试GraphQL API
      • 测试GraphQL API
      • 什么是GraphQL?
    • 服务器端模板注入
      • 服务器端模板注入
      • 利用服务器端模板注入漏洞
    • Web缓存投毒
      • Web缓存投毒
      • 缓存设计缺陷的利用
      • 缓存实现缺陷的利用
    • HTTP Host标头攻击
      • HTTP Host标头攻击
      • 如何识别和利用HTTP Host头的漏洞
      • 密码重置投毒
    • HTTP请求走私
      • HTTP请求走私
      • 查找HTTP请求走私漏洞
      • 利用HTTP请求走私漏洞
      • 高级请求走私
        • 高级请求走私
        • HTTP/2降级
        • 响应队列投毒
        • HTTP/2专属载体
        • HTTP请求隧道
      • 浏览器驱动的请求伪造
        • 浏览器驱动的请求伪造
        • CL.0请求走私
        • 客户端异步攻击
        • 基于暂停的异步攻击
    • OAuth认证
      • OAuth 2.0认证漏洞
      • OAuth授权类型
      • OpenID Connect
      • 如何防范OAuth认证漏洞
    • JWT攻击
      • JWT攻击
      • 在Burp Suite中使用JWT
      • 算法混淆攻击
    • 原型污染
      • 什么是原型污染?
      • JavaScript原型和继承
      • 客户端
        • 客户端原型污染漏洞
        • 通过浏览器API进行原型污染
      • 服务器端
        • 服务器端原型污染
      • 预防原型污染漏洞
    • 基本技能
      • 基本技能
      • 使用编码混淆攻击
      • 在手动测试中使用Burp Scanner
Powered by GitBook
On this page
  • 什么是SQL注入(SQLi)?
  • 一次成功的SQL注入攻击有什么影响?
  • SQL注入示例
  • 检索隐藏数据
  • 破坏应用程序逻辑
  • 从其他数据库表中检索数据
  • 检查数据库
  • SQL盲注漏洞
  • 如何检测SQL注入漏洞
  • 查询中不同部分的SQL注入
  • 不同上下文中的SQL注入
  • 二阶SQL注入
  • 数据库特定因素
  • 如何防范SQL注入
  1. 服务器端主题
  2. SQL注入

SQL注入

PreviousSQL注入NextSQL注入UNION攻击

Last updated 1 year ago

在本节中,我们将讲解什么是SQL注入(SQLi),描述一些常见示例,解释如何发现和利用各种SQL注入漏洞,并总结如何防范SQL注入。

LAB

如果你已经熟悉SQLi漏洞背后的基本概念,并且只想在一些真实的、故意易受攻击的目标上练习利用它们,你可以从下面的链接中访问该主题中的所有实验。

什么是SQL注入(SQLi)?

SQL注入(SQLi)是一种Web安全漏洞,允许攻击者干扰应用程序对其数据库进行的查询。它通常允许攻击者查看他们一般无法检索到的数据。可能包括属于其他用户的数据,或应用程序本身能够访问的任何其他数据。在许多情况下,攻击者可以修改或删除这些数据,从而导致对应用程序的内容或行为产生持久性的更改。

在某些情况下,攻击者可以升级SQL注入攻击以破坏基础服务器或其他后端基础设施,或者执行拒绝服务攻击。

一次成功的SQL注入攻击有什么影响?

一次成功的SQL注入攻击可能导致对敏感数据的未授权访问,例如密码、信用卡详细信息或个人用户信息。近年来,许多知名数据泄露事件都是SQL注入攻击的结果,导致了声誉受损和监管罚款。在某些情况下,攻击者可以获得对组织系统的持久性后门访问,从而导致长期的威胁,可能在很长一段时间内不被察觉。

SQL注入示例

在不同情况下会出现各种各样的SQL注入漏洞、攻击和技术。一些常见的SQL注入示例包括:

  • 检索隐藏数据,可以修改SQL查询以返回额外的结果。

  • 破坏应用程序逻辑,可以更改查询以干扰应用程序的逻辑。

  • UNION攻击,可以从不同的数据库表中检索数据。

  • 检查数据库,可以提取有关数据库版本和结构的信息。

  • SQL盲注,即在应用程序的响应中不会返回你控制的查询结果。

检索隐藏数据

考虑一个显示不同类别产品的购物应用程序。当用户点击Gifts类别时,他们的浏览器会请求以下URL:

https://insecure-website.com/products?category=Gifts

这将导致应用程序对数据库进行SQL查询,以检索相关产品的详细信息:

SELECT * FROM products WHERE category = 'Gifts' AND released = 1

该SQL查询要求数据库返回:

  • 所有字段数据(*)

  • 来自products表

  • 产品类别是Gifts

  • 并且已发布的产品(released = 1)。

released = 1的限制是为了将未发布的产品隐藏起来。对于未发布的产品,想必是released = 0。

由于应用程序没有实施任何SQL注入攻击的防御措施,因此攻击者可以构造以下攻击:

https://insecure-website.com/products?category=Gifts'--

这将导致如下SQL查询:

SELECT * FROM products WHERE category = 'Gifts'--' AND released = 1

这里的关键是,双破折号--在SQL中是一个注释符,意味着剩余的查询条件被注释。这实际上删除了查询的其余部分,因此不再包含AND released = 1这个条件。也就意味着所有的产品都会被显示,包括未发布的产品。

更进一步,攻击者可以造成应用程序显示任意类别的所有产品,包括他们不知道的类别:

https://insecure-website.com/products?category=Gifts'+OR+1=1--

这导致如下SQL查询:

SELECT * FROM products WHERE category = 'Gifts' OR 1=1--' AND released = 1

修改后的查询将返回类别为Gifts或1等于1的所有商品。由于1 = 1始终为真,因此查询将返回所有商品。

警告

在向SQL查询中注入条件OR 1=1时要小心。尽管在你注入的初始上下文中可能是无害的,但应用程序常常在多个不同的查询中使用来自单个请求的数据。如果你的条件达到了UPDATE或DELETE语句,可能会导致数据意外丢失。

LAB

破坏应用程序逻辑

考虑一个允许用户使用用户名和密码登录的应用程序。如果用户提交了wiener的用户名和bluecheese的密码,应用程序会执行以下的SQL查询来检查凭据:

SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese'

如果查询返回了用户的详细信息,就会成功登录。否则就登录失败。

在这里,攻击者可以通过使用SQL注释序列--从查询的WHERE子句中删除密码检查,从而不用密码登录任意用户。例如,提交用户名administrator'--和空密码将执行如下查询:

SELECT * FROM users WHERE username = 'administrator'--' AND password = ''

该查询返回用户名为administrator的用户,并成功地将攻击者作为该用户登录。

LAB

从其他数据库表中检索数据

在应用程序的响应中返回了SQL查询结果的情况下,攻击者可以利用SQL注入漏洞从数据库的其他表中检索数据。这是通过UNION关键字实现的,它允许你执行一个额外的SELECT查询,并将结果附加到原始查询中。

例如,如果一个应用程序执行如下包含用户输入“Gifts”的查询:

SELECT name, description FROM products WHERE category = 'Gifts'

然后攻击者提交如下输入内容:

' UNION SELECT username, password FROM users--

这将导致应用程序返回所有的用户名和密码以及产品的名称和描述。

阅读更多

检查数据库

在初步识别出SQL注入漏洞后,获取有关数据库本身的一些信息通常特别有用。这些信息通常可以为进一步的利用铺平道路。

你可以查询数据库版本的详细信息。完成此操作的方式取决于数据库的类型,因此可以通过任一技术手段推断出数据库类型。例如,在Oracle中你可以执行:

SELECT * FROM v$version

还可以确定哪些数据库表存在以及包含哪些列。例如,在大多数数据库上,你可以执行以下查询列出表:

SELECT * FROM information_schema.tables

阅读更多

SQL盲注漏洞

很多SQL注入实例都是盲注漏洞。意味着应用程序不会在其响应中返回SQL查询的结果或任何数据库错误的细节。盲注漏洞仍然可以被利用来访问未经授权的数据,但所涉及的技术通常更复杂且难以执行。

根据漏洞的性质和所涉及的数据库,可以使用以下技术来利用SQL盲注漏洞:

  • 你可以改变查询的逻辑,根据单个条件的真假来触发应用程序响应中可检测到的差异。这可能涉及到在一些布尔逻辑中注入一个新的条件,或者有条件地触发一个诸如除以零之类的错误。

  • 你可以有条件地触发查询处理中的时间延迟,然后从应用程序响应时间上来判断条件是否生效;

  • 你可以使用OAST技术触发带外网络交互。该技术非常强大,可以在其他技术无法做到的情况下发挥作用。通常,可以通过带外通道直接泄露数据,例如,将数据放入你控制的域的DNS查询中。

阅读更多

如何检测SQL注入漏洞

使用Burp Suite的Web漏洞扫描器可以快速可靠地检测到大多数SQL注入漏洞。

可以通过使用系统化的一套测试针对应用程序中的每个入口点来手动检测SQL注入漏洞。通常包括:

  • 提交单引号字符',并查找错误或其他异常。

  • 提交一些特定于SQL的语法,以评估入口点的基本(原始)值和不同值,并在生成的应用程序响应中寻找系统差异。

  • 提交诸如OR 1=1和OR 1=2之类的布尔条件,并查找应用程序响应中的差异。

  • 提交旨在在SQL查询中执行时触发时间延迟的有效载荷,并寻找应时间的差异。

  • 提交旨在在SQL查询中执行时触发带外网络交互的OAST有效载荷,并监视任何由此产生的交互。

查询中不同部分的SQL注入

大多数SQL注入漏洞都出现在SELECT查询的WHERE子句中。这类SQL注入通常被经验丰富的测试人员很好地理解。

但是SQL注入漏洞原则上可以发生在查询的任何位置,也可以发生在不同的查询类型中。发生SQL注入最常见的其他位置包括:

  • 在UPDATE语句中,更新的值或WHERE子句中。

  • 在INSERT语句中,插入的值中。

  • 在SELECT语句中,表名或列名中。

  • 在SELECT语句中,ORDER BY子句中。

不同上下文中的SQL注入

到目前为止,你在所有实验中都使用查询字符串来注入恶意的SQL有效载荷。但是,请务必注意,你可以使用被应用程序处理为SQL查询的任何可控输入来执行SQL注入攻击。例如,一些网站以JSON或XML格式接收输入,并使用它来查询数据库。

这些不同的格式甚至可以为你提供替代方法,来混淆由于WAF和其他防御机制而被阻止的攻击。弱实现通常仅在请求中查找常见的SQL注入关键字,因此你可以通过简单地对被禁用的关键字中的字符进行编码或转义来绕过这些过滤。例如,以下基于XML的SQL注入使用XML转义序列对SELECT中的S字符进行编码:

<stockCheck>
    <productId>
        123
    </productId>
    <storeId>
        999 &#x53;ELECT * FROM information_schema.tables
    </storeId>
</stockCheck>

这将在服务器端进行解码,然后传递给SQL解释器。

LAB

二阶SQL注入

一阶SQL注入发生在应用程序从HTTP请求获取用户输入的情况下,并且在处理该请求的过程中,以不安全的方式将输入合并到SQL查询中。

在二阶SQL注入(也称为存储型SQL注入)中,应用程序从HTTP请求中获取用户输入并将其存储以备将来使用。通常,这是通过将输入放入数据库中来完成的,但在存储数据时不会出现漏洞。之后,在处理其他HTTP请求时,应用程序将以不安全的方式检索存储的数据并将其合并到SQL查询中。

二阶SQL注入通常出现在这样的情况下,开发人员意识到了SQL注入漏洞,从而安全地处理输入放入数据库的初始过程。当以后对数据进行处理时,由于先前已将其安全地放置到数据库中,因此认为该数据是安全的。此时数据的处理方式是不安全的,开发人员错误地认为数据是可信任的。

数据库特定因素

在主流的数据库平台上,SQL语言的某些核心功能以相同的方式实现,因此,检测和利用SQL注入漏洞的许多方式在不同类型的数据库上均相同。

但是,常见数据库之间也存在许多差异。意味着用于检测和利用SQL注入的某些技术在不同平台上的工作方式会有所不同。例如:

  • 字符串拼接的语法。

  • 注释。

  • 批处理(或堆叠)查询。

  • 特定于平台的API。

  • 错误信息。

阅读更多

如何防范SQL注入

通过使用参数化查询(也称为预编译语句)而不是在查询中进行字符串拼接,可以防范大多数SQL注入实例。

由于用户输入直接被拼接到查询中,因此以下代码容易受到SQL注入的攻击:

String query = "SELECT * FROM products WHERE category = '"+ input + "'";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query);

可以轻松地重写此代码以防范用户的输入干扰查询结构:

PreparedStatement statement = connection.prepareStatement("SELECT * FROM products WHERE category = ?");
statement.setString(1, input);
ResultSet resultSet = statement.executeQuery();

参数化查询可用于不受信任的输入作为查询中显示为数据的任何情况,包括WHERE子句和INSERT或UPDATE语句中的值。它们不能用于处理查询其他部分中不可信任的输入,例如表、列名或ORDER BY子句。将不受信任的数据放入这些查询部分的应用程序功能需要采用不同的方法,例如将允许的输入值列入白名单,或者使用不同的逻辑来实现所需的行为。

为了使参数化查询能够有效地防范SQL注入,查询中使用的字符串必须始终是一个硬编码常量,绝不能包含来自任何来源的任何变量数据。不要试图逐个决定数据项是否受信任,并在被认为安全的情况下继续在查询中使用字符串拼接。这样会很容易就数据的可能来源犯错误,或者其他代码的更改而违反有关数据受到污染的假设。

阅读更多

WHERE子句中的SQL注入漏洞允许检索隐藏数据
允许登录绕过的SQL注入漏洞
SQL注入UNION攻击
在SQL注入攻击中检查数据库
SQL注入速查表
SQL盲注
通过XML编码绕过过滤的SQL注入
SQL注入速查表
使用Burp Suite的Web漏洞扫描器发现SQL注入漏洞
查看所有SQL注入实验