示例1
2008年,大量web服务器使用同一SQL注入攻击字符串遭到破坏。这一字符串针对许多不同的程序。然后,SQL注入被用于修改网站以提供恶意代码。
示例2
以下代码动态构造并执行一个SQL查询,该查询搜索与指定名称匹配的项。查询将显示的项目限制为所有者与当前已验证用户的用户名匹配的项目。
...
string userName=ctx.getAuthenticatedUserName();
string query=“SELECT*FROM items WHERE owner='”+userName+“'AND itemname='”+itemname。文本+“”;
sda=新的SqlDataAdapter(查询,连接);
DataTable dt=新的DataTable();
星期四。填充(dt);
...
此代码打算执行的查询如下:
但是,由于查询是通过连接常量基查询字符串和用户输入字符串来动态构造的,因此只有当itemName不包含单引号字符时,查询才能正常运行。如果用户名为wiley的攻击者输入字符串:
对于itemName,则查询如下:
SELECT*FROM items WHERE owner='wiley'AND itemname='name'OR'a'='a';从项目中选择*;
增加了:
条件导致WHERE子句的计算结果始终为true,因此查询在逻辑上与更简单的查询等效:
对查询的这种简化允许攻击者绕过查询只返回经过身份验证的用户拥有的项目的要求;查询现在返回存储在items表中的所有条目,而不管其指定的所有者是谁。
示例3
此示例检查传递给上一示例中构造和执行的查询的不同恶意值的影响。
如果用户名为wiley的攻击者输入字符串:
对于itemName,则查询成为以下两个查询:
SELECT*FROM items WHERE owner='wiley'AND itemname='name';从项目中选择*;
删除项目;
--'
许多数据库服务器,包括Microsoft(R)SQL Server 2000,都允许同时执行多个用分号分隔的SQL语句。虽然此攻击字符串会在Oracle和其他不允许批量执行以分号分隔的语句的数据库服务器上导致错误,但在允许批量执行的数据库上,此类攻击允许攻击者对数据库执行任意命令。
请注意后面的一对连字符(--),它向大多数数据库服务器指定语句的其余部分将被视为注释而不执行。在这种情况下,注释字符用于删除修改后的查询中剩余的尾随单引号。在不允许以这种方式使用注释的数据库上,使用与前一示例中所示类似的技巧仍然可以使一般攻击有效。
如果攻击者输入字符串
名称';删除项目;SELECT*FROM items WHERE“a”=“a”
然后将创建以下三个有效语句:
SELECT*FROM items WHERE owner='wiley'AND itemname='name';从项目中选择*;
删除项目;
SELECT*FROM items WHERE'a'='a';
防止SQL注入攻击的一种传统方法是将其作为输入验证问题进行处理,要么只接受安全值允许列表中的字符,要么识别并逃离潜在恶意值的denylist。允许列表可以是强制执行严格的输入验证规则的一种非常有效的方法,但参数化SQL语句需要较少的维护,并且可以在安全性方面提供更多的保证。几乎总是这样,拒绝列表中充满了漏洞,使得它无法有效地防止SQL注入攻击。例如,攻击者可以:
-
未引用的目标字段
-
寻找方法绕过对某些转义元字符的需要
-
使用存储过程隐藏注入的元字符。
手动转义SQL查询输入中的字符可能会有所帮助,但这不会使应用程序免受SQL注入攻击。
另一种常见的处理SQL注入攻击的解决方案是使用存储过程。尽管存储过程可以防止某些类型的SQL注入攻击,但它们不能防止其他许多攻击。例如,以下PL/SQL过程容易受到与第一个示例中相同的SQL注入攻击。
程序get_item(itm_cv IN OUT ItmCurTyp,在varchar2中为usr,在varchar2中为itm)
为打开itm_cv
'SELECT*FROM items WHERE'||'owner='||usr||'AND itemname='||itm||';
结束get_item;
存储过程通常通过限制可以传递到其参数的语句类型来帮助防止SQL注入攻击。然而,有很多方法可以绕过这些限制,还有许多有趣的语句仍然可以传递给存储过程。同样,存储过程可以防止一些攻击,但它们不会使您的应用程序免受SQL注入攻击。
示例4
MS SQL有一个内置函数,可以执行shell命令。在这种情况下,SQL注入可能是灾难性的。例如,表单查询:
选择商品,从产品定价,其中ITEM_CATEGORY=“$user_input”按价格订购
其中$user_input来自不受信任的源。
如果用户提供字符串:
'; 执行主机。。xp_cmdshell“目录”--
查询将采用以下形式:
SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=“”;执行主机。。xp_cmdshell'dir'--'按价格订购
现在,这个查询可以分解为:
-
第一个SQL查询:SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=“”;
-
第二个SQL查询,在shell:exec master中执行dir命令。。xp_cmdshell“目录”
-
MS SQL注释:--'按价格订购
可以看出,恶意输入将查询的语义更改为查询、shell命令执行和注释。
示例5
此代码旨在打印给定消息ID的消息摘要。
$id=$_COOKIE[“中间”];
mysql_query(“SELECT MessageID,Subject FROM messages WHERE MessageID='$id'”);
程序员可能在假定攻击者无法修改cookie的情况下跳过了对$id的任何输入验证。然而,使用自定义客户端代码甚至在web浏览器中都很容易做到这一点。
虽然$id在对mysql_query()的调用中用单引号括起来,但攻击者只需将传入的mid-cookie更改为:
这将生成结果查询:
SELECT MessageID,Subject FROM消息WHERE MessageID=“1432”或“1”=“1”
这不仅将检索1432号消息,还将检索所有其他消息。
在这种情况下,程序员可以对代码进行简单修改,以消除SQL注入:
$id=intval($_COOKIE[“mid”]);
mysql_query(“SELECT MessageID,Subject FROM messages WHERE MessageID='$id'”);
然而,如果此代码旨在支持具有不同消息框的多个用户,则代码可能还需要进行访问控制检查(CWE-285型)以确保应用程序用户具有查看该消息的权限。
示例6
本例尝试使用用户提供的姓氏并将其输入数据库。
$userKey=获取用户ID();
$name=获取用户输入();
#确保只允许使用字母、连字符和撇号
$name=allowList($name,“^a-zA-z'-$”);
$query=“INSERT INTO last_names VALUES('$userKey','$name')”;
虽然程序员将allowlist应用于用户输入,但它有缺点。首先,用户仍然可以提供连字符,在SQL中用作注释结构。如果用户指定“--”,则语句的其余部分将被视为注释,这可能会绕过安全逻辑。此外,allowlist允许撇号,这也是SQL中的数据/命令分隔符。如果用户提供带撇号的名称,他们可能会更改整个语句的结构,甚至更改程序的控制流,可能会访问或修改机密信息。在这种情况下,连字符和撇号都是姓氏的合法字符,需要允许使用它们。相反,程序员可能希望使用准备好的语句或对输入应用编码例程,以防止任何数据/指令误解。