专栏首页马洪彪Fortify Audit Workbench 笔记 SQL Injection SQL注入

Fortify Audit Workbench 笔记 SQL Injection SQL注入

SQL Injection SQL注入

Abstract

通过不可信来源的输入构建动态 SQL 指令,攻击者就能够修改指令的含义或者执行任意 SQL 命令。

Explanation

SQL injection 错误在以下情况下发生:

  1. 数据从一个不可信赖的数据源进入程序。
  2. 数据用于动态地构造一个 SQL 查询。 例1: 以下代码动态地构造并执行了一个SQL查询,该查询可以搜索与指定名称相匹配的项。 该查询仅会显示条目所有者与被授予权限的当前用户一致的条目。
...
String userName = ctx.getAuthenticatedUserName();
String itemName = request.getParameter("itemName");
String query = "SELECT * FROM items WHERE owner = '"
+ userName + "' AND itemname = '"
+ itemName + "'";
ResultSet rs = stmt.execute(query);
...

这一代码所执行的查询遵循如下方式:

SELECT * FROM items
WHERE owner = <userName>
AND itemname = <itemName>;

但是,由于这个查询是动态构造的,由一个常数基查询字符串和一个用户输入字符串连接而成,因此只有在itemName 不包含单引号字符时,才会正确执行这一查询。 如果一个用户名为 wiley 的攻击者在 itemName 中输入字符串 "name' OR 'a'='a",那么构造的查询就会变成:

SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name' OR 'a'='a';

附加条件 OR 'a'='a' 会使 where 从句永远评估为 true,因此该查询在逻辑上将等同于一个更为简化的查询:

SELECT * FROM items;

这种查询的简化会使攻击者绕过查询只返回经过验证的用户所拥有的条目的要求;而现在的查询则会直接返回所有储存在 items 表中的条目,不论它们的所有者是谁。 例 2: 这个例子指出了将不同的恶意数值传递给在例 1 中构造和执行的查询时所带来的各种影响。如果一个用户名为 wiley 的攻击者在 itemName 中输入字符串“name'; DELETE FROM items; --”,那么最后构造的查询将变成两个:

SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
--'

众多数据库服务器,其中包括 Microsoft(R) SQL Server 2000,都可以一次性执行多条用分号分隔的 SQL 指令。 对于那些不允许运行用分号分隔的批量 SQL 指令的数据库服务器,比如 Oracle 和其他数据库服务器,攻击者输入的这个字符串只会导致错误;但是在那些支持这种操作的数据库服务器上,攻击者可能会通过执行多条 SQL 而在数据库上执行任意 SQL 指令。 注意成对的连字符 (--);这在大多数数据库服务器上都表示下面的语句将作为注释使用,而不能加以执行 [4]。 在这种情况下,注释字符的作用就是删除修改的查询指令中遗留的最后一个单引号。 而在那些不允许这样加注注释的数据库中,通常攻击者可以如例 1 那样来攻击。如果攻击者输入字符串 “name'); DELETE FROM items; SELECT * FROM items WHERE 'a'='a” 就会创建如下三个有效的 SQL 指令:

SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
SELECT * FROM items WHERE 'a'='a';

避免 SQL injection 攻击的传统方法之一是,把它作为一个输入合法性检查的问题来处理,只接受列在白名单中的字符,或者识别并避免那些列在黑名单中的恶意数据。 白名单方法是一种非常有效方法,它可以强制执行严格的输入检查规则,但是参数化的 SQL 指令所需维护更少,而且能提供更好的安全保障。 而对于通常采用的列黑名单方式,由于总是存在一些小漏洞,所以并不能有效地防止 SQL injection 威胁。 例如,攻击者可以: — 把没有被黑名单引用的值作为目标 — 寻找方法以绕过对某一转义序列元字符的需要 — 使用存储过程来隐藏注入的元字符 手动去除 SQL 查询中的元字符有一定的帮助,但是并不能完全保护您的应用程序免受SQL injection 攻击。 防范 SQL injection 攻击的另外一种常用方式是使用存储过程。 虽然存储过程可以阻止某些类型的 SQL injection 攻击,但是对于绝大多数攻击仍无能为力。 存储过程有助于避免 SQL injection 的常用方式是限制可作为参数传入的指令类型。 但是,有许多方法都可以绕过这一限制,许多危险的表达式仍可以传入存储过程。 所以再次强调,存储过程可以避免部分情况,但是并不能完全保护您的应用系统抵御SQL injection 的攻击。

Recommendation

造成 SQL injection 攻击的根本原因在于攻击者可以改变 SQL 查询的上下文,使程序员原本要作为数据解析的数值,被篡改为命令了。 当构造一个 SQL 查询时,程序员应当清楚,哪些输入的数据将会成为命令的一部分, 而哪些仅仅是作为数据。 参数化 SQL 指令可以防止直接窜改上下文,避免几乎所有的 SQL injection 攻击。 参数化 SQL 指令是用常规的 SQL 字符串构造的,但是当需要加入用户输入的数据时,它们就需要使用捆绑参数,这些捆绑参数是一些占位符,用来存放随后插入的数据。 换言之,捆绑参数可以使程序员清楚地分辨数据库中的数据,即其中有哪些输入可以看作命令的一部分,哪些输入可以看作数据。 这样,当程序准备执行某个指令时,它可以详细地告知数据库,每一个捆绑参数所使用的运行时的值,而不会被解析成对该命令的修改。 前面的例子可以改成使用参数化 SQL 指令的攻击方式(替代用户输入连续的字符串),如下所示:

...
String userName = ctx.getAuthenticatedUserName();
String itemName = request.getParameter("itemName");
String query =
"SELECT * FROM items WHERE itemname=? AND owner=?";
PreparedStatement stmt = conn.prepareStatement(query);
stmt.setString(1, itemName);
stmt.setString(2, userName);
ResultSet results = stmt.execute();
...

更加复杂的情况常常出现在报表生成代码中,因为这时需要通过用户输入来改变 SQL 指令的命令结构,比如在 WHERE 条件子句中加入动态的约束条件。 不要因为这一需求,就无条件地接受连续的用户输入,从而创建查询语句字符串。 当必须要根据用户输入来改变命令结构时,可以使用间接的方法来防止 SQL injection 攻击: 创建一个合法的字符串集合,使其对应于可能要加入到 SQL 指令中的不同元素。 在构造一个 SQL 指令时, 让用户从这个集合中去选择字符串,因为这个集合的字符串在系统的控制之内。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Fortify Audit Workbench 笔记 Access Control: Database

    如果没有适当的 access control,就会执行一个包含用户控制主键的 SQL 指令,从而允许攻击者访问未经授权的记录。

    用户1637609
  • Fortify Audit Workbench 笔记 Unreleased Resource: Database( 未释放资源:数据库)

    程序可能无法成功释放某一项系统资源。 资源泄露至少有两种常见的原因: - 错误状况及其他异常情况。 - 未明确程序的哪一部份负责释放资源。 大部分 Unr...

    用户1637609
  • Java JDBC SqlServer

    一、驱动 下载地址:https://www.microsoft.com/en-us/download/details.aspx?id=11774 引用Jar包时...

    用户1637609
  • 一个"TOP SQL"类产品的构想

    作为一名DBA,SQL优化是工作中必不可少的部分。如何快速、准确的发现待优化的语句,是DBA经常需要考虑的问题。很多数据库都内置有慢查询、SQL报告等能力,这也...

    用户5548425
  • 数据蒋堂 | SQL是描述性语言?

    本文共1200字,建议阅读8分钟。 用SQL写代码时一般不用再关心变量、循环的具体动作,但要操心表、字段这些概念上的计算过程。

    数据派THU
  • 移动下SQL中的表位置,性能提高18倍

    平日里2-3秒搞定的SQL,这会非得弄个7-8秒。timeout更是频频爆出。搞得办公室怨叫声此起彼伏,真有点《生命协奏曲》的味道。

    Lenis
  • 【SQL】历史SQL监控(Historical SQL Monitoring ) 功能(12c)

    Oracle 11g版本 推出了实时SQL监控功能(Real-Time SQL Monitoring),用于实时地监视执行中SQL的性能;Oracle 12c ...

    TeacherWhat
  • 【SQL Performance】实时SQL监控功能(Real-Time SQL Monitoring)

    实时SQL监控功能(Real-Time SQL Monitoring)是Oracle11g推出的功能,通过这个功能可以实时地监视执行中的SQL性能。

    TeacherWhat
  • 45岁的 SQL 语言要被淘汰了?

    在 SQL 被引入的 45 年中,它经历了许多数据库的诞生和消亡,也经历了许多数据处理方式的诞生和消亡。

    Java技术栈
  • 验证GaussDB T 闪回事务查询功能;闪回表功能强劲闪回TRUNCATE

    总的来说,gaussdb100 T 是可以支持闪回事务查询。 二、GaussDB T 的 Flashback Table 功能非常强劲可以闪回TRUNCATE...

    数据和云

扫码关注云+社区

领取腾讯云代金券