PHP安全 – SQL注入 » FreeWAF

«

»

17

PHP安全 – SQL注入

PHP安全 – SQL注入

很多web开发者没有注意到SQL查询是可以被篡改的,因而把SQL查询当作可信任的命令。殊不知道,SQL查询可以绕开访问控制,从而绕过身份验证和权限检查。更有甚者,有可能通过SQL查询去运行主机操作系统级的命令。

直接SQL命令注入就是攻击者常用的一种创建或修改已有SQL语句的技术,从而达到取得隐藏数据,或覆盖关键的值,甚至执行数据库主机操作系统命令的目的。这是通过应用程序取得用户输入并与静态参数组合成SQL查询来实现的。下面将会给出一些真实的例子。

举例说明

由于在缺乏对输入的数据进行验证,并且使用了超级用户或其它有权创建新用户的数据库帐号来连接,攻击者可以在数据库中新建一个超级用户。

例1:一段实现数据分页显示的代码,也可以被用作创建一个超级用户(PostgreSQL)。

<?php

$offset = $argv[0]; //beware, no input validation!

$query = “SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;”;

$result = pg_query($conn, $query);

?>

一般的用户会点击$offset已被斌值的“上一页”、“下一页”的链接。原本代码只会认为$offset是一个数值。然而,如果有人尝试把以下语句先经过urlencode()处理,然后加入URL中的话:

0;

insert into pg_shadow(usename, usesysid, usesuper, usecatupd, passwd) select ‘crack’, usesysid, ‘t’,'t’,'crack’ from pg_shadow where usename = ‘postgres’;

那么他就可以创建一个超级用户了。注意那个0;只不过是为了提供一个正确的偏移量以便补充完整原来的查询,使它不要出错而已。

注意:– 是SQL的注释标记,一般可以使用来它告诉SQL解释器忽略后面的语句。

对显示搜索结果的页面下手是一个能得到密码的可行办法。攻击者所要做的只不过是找出哪些提交上去的变量是用于 SQL 语句并且处理不当的。而这类的变量通常都被用于 SELECT 查询中的条件语句,如 WHERE, ORDER BY, LIMIT 和 OFFSET。如果数据库支持 UNION 构造的话,攻击者还可能会把一个完整的 SQL 查询附加到原来的语句上以便从任意数据表中得到密码。因此,对密码字段加密是很重要的。

例2:显示文章,以及一些密码(任何数据库系统)。

<?php

$query = “SELECT id, name, inserted, size FROM products WHERE size = ‘$size’ ORDER BY $order LIMIT $limit, $offset;”;

$result = odbc_exec($conn, $query);

?>

可以在原来的查询的基础上添加另一个 SELECT 查询来获得密码:

union select ’1′, concat(uname||’-'||passwd) as name, ’1971-01-01′, ’0′ from usertable;

假如上述语句(使用’和–)被加入到$query中的任意一个变量的话,那么就麻烦了。

SQL 中的 UPDATE 也会受到攻击。这种查询也可能像上面的例子那样被插入或附加上另一个完整的请求。但是攻击者更愿意对 SET 子句下手,这样他们就可以更改数据表中的一些数据。这种情况下必须要知道数据库的结构才能修改查询成功进行。可以通过表单上的变量名对字段进行猜测,或者进行暴力破解。对于存放用户名和密码的字段,命名的方法并不多。

例3:从重设密码,到获得更多权限(任何数据库系统)

<?php

$query = “UPDATE usertable SET pwd=’$pwd’ WHERE uid=’$uid’;”;

?>

但是恶意的用户会把 ‘or uid like ‘%admin%’; — 作为变量的值提交给 $uid 来改变 admin 的密码,或者把 $pwd 的值提交为 “hehehe’, admin=’yes’, trusted=100 “(后面有个空格)去获得更多的权限。这样做的话,查询语句实际上就变成了:

<?php

// $uid == ‘ or uid like’%admin%’; –

$query = “UPDATE usertable SET pwd=’…’ WHERE uid=” or uid like ‘%admin%’; –”;

// $pwd == “hehehe’, admin=’yes’, trusted=100 ”

$query = “UPDATE usertable SET pwd=’hehehe’, admin=’yes’, trusted=100 WHERE

…;”;

?>

下面这个可怕的例子将会演示如何在某些数据库上执行系统命令。

例4:攻击数据库所在主机的操作系统(MSSQL Server)

<?php

$query = “SELECT * FROM products WHERE id LIKE ‘%$prod%’”;

$result = mssql_query($query);

?>

如果攻击提交 a%’ exec master..xp_cmdshell ‘net user test testpass /ADD’ — 作为变量 $prod的值,那么 $query 将会变成:

<?php

$query = “SELECT * FROM products WHERE id LIKE ‘%a%’

exec master..xp_cmdshell ‘net user test testpass /ADD’–”;

$result = mssql_query($query);

?>

MSSQL 服务器会执行这条 SQL 语句,包括它后面那个用于向系统添加用户的命令。如果这个程序是以 sa 运行而 MSSQLSERVER 服务又有足够的权限的话,攻击者就可以获得一个系统帐号来访问主机了。

注意:上述例子都是基于一定的数据库系统,但是这不说明这些攻击就不会发生在其他的数据库产品上。你的数据库服务器的弱点可能以其他的方式存在。

看图小故事

 看图1

 看图2

 

一天,学校跟家长打电话:

学校:你好,这里是你儿子所在的学校,我们这里的计算机系统出了点问题。

家长:哦,天啊,他是不是打坏了什么东西,以某种方式?

学校:你儿子的名字真的叫做Robert’); DROP TBALE Students;– 吗?

家长:哦,是的,我们叫他小BOBBY表。

学校:好吧,我们丢失了这一年的学生表记录,你高兴了吧。

家长:那我希望你们学会在操作数据库时,对输入进行过滤哦。

预防措施

也许有人会自我安慰,说攻击者要知道数据库结构的信息才能实施上面的攻击。没错,确实如此。但没人能保证攻击者一定得不到这些信息,一旦他们得到了,数据库有泄露的危险。如果你在用开放源代码的软件包来访问数据库,比如论坛程序,攻击者就很容得到到相关的代码。如果这些代码设计不良的话,风险就更大了。

  • 这些攻击总是建立在发掘安全意识不强的代码上的。所以,永远不要信任外界输入的数据,特别是来自于客户端的,包括选择框、表单隐藏域和cookie。就如上面的第一个例子那样,就算是正常的查询也有可能造成灾难。
  • 永远不要使用超级用户或所有者帐号去连接数据库。要用权限被严格限制的帐号。
  • 检查输入的数据是否具有所期望的数据格式。PHP有很多可以用于检查输入的函数,从简单的变量函数和字符类型函数(比如is_numeric(),ctype_digit())到复杂的Perl兼容正则表达式函数都可以完成这个工作。
  • 如果程序等待输入一个数字,可以考虑使用 is_numeric() 来检查,或者直接使用 settype() 来转换它的类型,也可以用 sprintf() 把它格式化为数字。
  • 使用数据库特定的敏感字符转义函数,比如mysql_escape_string()和sql_escape_string()。把用户提交上来的非数字数据进行转义。如果数据库没有专门的敏感字符转义功能的话 addslashes() 和 str_replace() 可以代替完成这个工作。看看第一个例子,此例显示仅在查询的静态部分加上引号是不够的,查询很容易被攻破。
  • 要不择手段避免显示出任何有关数据库的信心,尤其是数据库结构。参见错误报告和错误处理函数。
  • 也可以选择使用数据库的存储过程和预定义指针等特性来抽象数库访问,使用户不能直接访问数据表和视图。但这个办法又有别的影响。
  • 除此之外,在允许的情况下,使用代码或数据库系统保存查询日志也是一个好办法。显然,日志并不能防止任何攻击,但利用它可以跟踪到哪个程序曾经被尝试攻击过。日志本身没用,要查阅其中包含的信息才行。毕竟,更多的信息总比没有要好。

该文章英文原文来源自http://php.net/manual/en/security.database.sql-injection.php。

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>