mysql注入攻击及防范
2013-09-03 11:29
330 查看
一、注入攻击种类 1. GET注入 输入参数通过URL发送。 2. POST注入 输入参数通过HTTP正文发送 3. COOKIE注入 输入参数通过HTTP cookie发送 4. HTTP Headers注入 通过http提交应用程序时使用的头 二、各种攻击所占比及防范程度 1. 漏洞发现占比
从上图中,可以看到,大部分的http header和http cookie漏洞不能被发现。 2. 漏洞防范占比
从上图中,可以得出,大部分的攻击防范上,在于get和post,而对于cookie和header则很少,因此很容易在这方面失守。 三、注入攻击实验分析 1. 创建实验数据库,分两种类型编码:GBK/UTF8 其中对于多字节编码的数据库,数据在PHP层转义时,GBK存在BUG,因此可以进行测试对比。 2. 初始化数据库 其中构建一个简单表,放几行简单的数据,用于测试。 3. 构建测试代码 以上代码构建了两种编码(gbk/utf8),执行逻辑分四种实现方式,各四种访问方式,其中第一种为正常访问,后三种分别为注入型写法。
4. 四种实现写法 5. 应对攻击的表现 从上面可以很明确的看到,在所传参数中,带有注入性语句。表现结果: GBK编码:
UTF8编码:
从中可以看到,两种编码的数据库中,对于 SQL1 的写法是实现了成功注入。 从测试的结果中,可以知道,对于两种编码,都实现了对 SQL2 写法的注入攻击。 其中在链接中输出 chr(0xbf) . chr(0x27) ,主要是为了测试多字节编码的值,经过转义后,对于GBK存在BUG,addslashes处理后,前一个字符会被转义为一个多字节的合法字符,而后面的 chr(0x27) 则自动成了一个单引号,从而实现字符串截断,造成注入。而相对于GBK,UTF8编码的数据库,在编码转义过程中,不存在该问题。 GBK表现(注入成功)
UTF8表现
对于第三种写法,因为 ID 在查询过程中,明确是整型数值,因此,在查询前,强制进行整型校验,所以在这几种攻击方式中,都没能实现注入,因此,对于此种类型的数据查询条件,为了安全,我们可以进行相应的校验,从而保证安全,但对于其他类型的变量,则不太好处理。 综合上面的几种表现,最好的方式是以 PDO 方式来实现数据库的查询逻辑,只需注意以下几点即可: 1. 参数 PDO::ATTR_EMULATE_PREPARES 设置为 false; 2. 你不能让占位符 ? 代替一组值,如:SELECT * FROM blog WHERE userid IN ( ? ); 3. 你不能让占位符代替数据表名或列名,如:SELECT * FROM blog ORDER BY ?; 4. 你不能让占位符 ? 代替任何其他SQL语法,如:SELECT EXTRACT( ? FROM datetime_column) AS variable_datetime_element FROM blog; 四、总结 sql注入,可以从多方面来进行防范,在可能的情况下,如果数据库需要存储多字节字符,建议数据库的编码方式尽量采用UTF8;另外,在查询数据库的逻辑实现过程中,我们要加强对于语句编写方面的一些安全意识,如,对于整型数值进行强制性的类型校验等;在解决方案上,建议采用 PDO 方式来实现相关的数据库操作逻辑。 而对于另外几种攻击方式,区别在于传送攻击的方式不同,原理还是一样,所以不再赘叙。 附件: 测试实验文件:http://pan.baidu.com/share/link?shareid=963562568&uk=1090915711
从上图中,可以看到,大部分的http header和http cookie漏洞不能被发现。 2. 漏洞防范占比
从上图中,可以得出,大部分的攻击防范上,在于get和post,而对于cookie和header则很少,因此很容易在这方面失守。 三、注入攻击实验分析 1. 创建实验数据库,分两种类型编码:GBK/UTF8
$createSqlGbk = "CREATE TABLE `user` (`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '用户ID' ,`username` varchar(32) NOT NULL COMMENT '用户名' ,`password` varchar(32) NOT NULL ,`remark` text NULL ,PRIMARY KEY (`id`)) DEFAULT CHARACTER SET=gbk";
$createSqlUtf8 = "CREATE TABLE `user` (`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '用户ID' ,`username` varchar(32) NOT NULL COMMENT '用户名' ,`password` varchar(32) NOT NULL ,`remark` text NULL ,PRIMARY KEY (`id`)) DEFAULT CHARACTER SET=utf8";
$insertDataSql = "INSERT INTO `user` VALUES ('1', 'test', '123456', null), ('2', 'guest', '888888', null), ('3', 'admin', '888888', null)";
<html> <head> <title>SQL注入攻击与防范</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <style> body{font-size:12px;margin:20px;} h3{font-size:14px;margin:20px 0;} a{font-size:12px;margin:10px 20px;} </style> </head> <body> <h3>SQL注入攻击(GBK)</h3> <a href="./inject.php?type=gbk&id=1">正常取值</a> <a href="./inject.php?type=gbk&id=2341 or 1 = 1 -- dasf">SQL注入(针对直接等于写法)</a> <a href="./inject.php?type=gbk&id=2341' or 1 = 1 -- asdf">SQL注入(针对用引号包括写法)</a> <a href="./inject.php?type=gbk&isslashes=1&id=2341<?php echo chr(0xbf) . chr(0x27); ?> or 1 = 1 -- asd">SQL注入(针对对特殊字符转义写法)</a> <h3>SQL注入攻击(UTF8)</h3> <a href="./inject.php?type=utf8&id=1">正常取值</a> <a href="./inject.php?type=utf8&id=2341 or 1 = 1 -- dasf">SQL注入(针对直接等于写法)</a> <a href="./inject.php?type=utf8&id=2341' or 1 = 1 -- asdf">SQL注入(针对用引号包括写法)</a> <a href="./inject.php?type=utf8&isslashes=1&id=2341<?php echo chr(0xbf) . chr(0x27); ?> or 1 = 1 -- asd">SQL注入(针对对特殊字符转义写法)</a> <div style="width:100%;height:5px;margin:10px 0px;clear:both;background-color:gray;"></div> <?php if (isset($_GET['type'])) { $type = $_GET['type']; } else { exit(); } echo "<h1 style='font-size:12px;'>CHARSET:: <b style='color:red;font-size:18px;'>" . $type . "</b></h1>"; // 建立mysql连接 $c = mysql_connect("localhost", "root", ""); echo "<h1 style='font-size:14px;color:red;'>SQL注入攻击及防范</h1>"; if (isset($_GET['id'])) { if (isset($_GET['isslashes'])) { $id = addslashes($_GET['id']); } else { $id = $_GET['id']; } // 三种sql写法 $sql1 = "SELECT * FROM user WHERE id = $id"; $sql2 = "SELECT * FROM user WHERE id = '{$id}'"; $sql = "SELECT * FROM user WHERE id = " . intval($id); } //根据编码不同,选择连接对应编码数据库 if ($type == 'gbk') { mysql_select_db("testInjectionDb_gbk", $c); // change our character set mysql_query("SET CHARACTER SET 'gbk'", $c); } else { mysql_select_db("testInjectionDb_utf8", $c); // change our character set mysql_query("SET CHARACTER SET 'utf8'", $c); } // 依次执行三种写法的查询 echo "<div style='font-size:12px;'>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++</div>"; echo "<h1 style='font-size:12px;'>被攻击 SQL1:: <b style='color:red;font-size:14px;'>" . $sql1 . "</b></h1>"; $r1 = mysql_query($sql1, $c); if ($r1) { echo "<h1 style='font-size:12px;color:green;'>影响数据条数:: <b style='color:red;font-size:18px;'>" . mysql_num_rows($r1) . "</b></h1>"; } else { echo "<h1 style='font-size:12px;color:red;'>语法错误!</h1>"; } echo "<div style='font-size:12px;'>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++</div>"; echo "<h1 style='font-size:12px;'>被攻击 SQL2:: <b style='color:red;font-size:14px;'>" . $sql2 . "</b></h1>"; $r2 = mysql_query($sql2, $c); if ($r2) { echo "<h1 style='font-size:12px;color:green;'>影响数据条数:: <b style='color:red;font-size:18px;'>" . mysql_num_rows($r2) . "</b></h1>"; } else { echo "<h1 style='font-size:12px;color:red;'>语法错误!</h1>"; } echo "<div style='font-size:12px;'>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++</div>"; echo "<h1 style='font-size:12px;'>强制整型较验 SQL:: <b style='color:red;font-size:14px;'>" . $sql . "</b></h1>"; $r = mysql_query($sql, $c); if ($r) { echo "<h1 style='font-size:12px;color:green;'>影响数据条数:: <b style='color:red;font-size:18px;'>" . mysql_num_rows($r) . "</b></h1>"; } else { echo "<h1 style='font-size:12px;color:red;'>语法错误!</h1>"; } // 建立PDO的连接,万能防注入。 // 注意: // 1. 参数 PDO::ATTR_EMULATE_PREPARES 设置为 false; // 2. 你不能让占位符 ? 代替一组值,如:SELECT * FROM blog WHERE userid IN ( ? ); // 3. 你不能让占位符代替数据表名或列名,如:SELECT * FROM blog ORDER BY ?; // 4. 你不能让占位符 ? 代替任何其他SQL语法,如:SELECT EXTRACT( ? FROM datetime_column) AS variable_datetime_element FROM blog; echo "<div style='font-size:12px;'>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++</div>"; if ($type == 'gbk') { $pdo = new PDO("mysql:host=localhost;dbname=testInjectionDb_gbk", "root", ""); } else { $pdo = new PDO("mysql:host=localhost;dbname=testInjectionDb_utf8", "root", ""); } $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE); $st = $pdo->prepare("SELECT * FROM user WHERE id = ?"); $st->bindParam(1, $id); $c = $st->execute(); echo "<h1 style='font-size:12px;'>PDO防注入(万能防注入) SQL:: <b style='color:red;font-size:14px;'>" . $st->queryString . "</b></h1>"; if ($c) { $rs = $st->fetchAll(); echo "<h1 style='font-size:12px;color:green;'>影响数据条数:: <b style='color:red;font-size:18px;'>" . count($rs) . "</b></h1>"; var_dump($rs); $st->debugDumpParams(); } else { echo "<h1 style='font-size:12px;color:red;'>语法错误!</h1>"; } ?> </body> </html>
4. 四种实现写法
$sql1 = "SELECT * FROM user WHERE id = $id";$sql2 = "SELECT * FROM user WHERE id = '{$id}'";$sql = "SELECT * FROM user WHERE id = " . intval($id);
$st = $pdo->prepare("SELECT * FROM user WHERE id = ?");$st->bindParam(1, $id);$c = $st->execute();
<a href="./inject.php?type=gbk&id=2341 or 1 = 1 -- dasf">SQL注入(针对直接等于写法)</a>
<a href="./inject.php?type=utf8&id=2341 or 1 = 1 -- dasf">SQL注入(针对直接等于写法)</a>
UTF8编码:
从中可以看到,两种编码的数据库中,对于 SQL1 的写法是实现了成功注入。
<a href="./inject.php?type=gbk&id=2341' or 1 = 1 -- asdf">SQL注入(针对用引号包括写法)</a>
<a href="./inject.php?type=utf8&id=2341' or 1 = 1 -- asdf">SQL注入(针对用引号包括写法)</a>
<a href="./inject.php?type=gbk&isslashes=1&id=2341<?php echo chr(0xbf) . chr(0x27); ?> or 1 = 1 -- asd">SQL注入(针对对特殊字符转义写法)</a>
<a href="./inject.php?type=utf8&isslashes=1&id=2341<?php echo chr(0xbf) . chr(0x27); ?> or 1 = 1 -- asd">SQL注入(针对对特殊字符转义写法)</a>
UTF8表现
对于第三种写法,因为 ID 在查询过程中,明确是整型数值,因此,在查询前,强制进行整型校验,所以在这几种攻击方式中,都没能实现注入,因此,对于此种类型的数据查询条件,为了安全,我们可以进行相应的校验,从而保证安全,但对于其他类型的变量,则不太好处理。 综合上面的几种表现,最好的方式是以 PDO 方式来实现数据库的查询逻辑,只需注意以下几点即可: 1. 参数 PDO::ATTR_EMULATE_PREPARES 设置为 false; 2. 你不能让占位符 ? 代替一组值,如:SELECT * FROM blog WHERE userid IN ( ? ); 3. 你不能让占位符代替数据表名或列名,如:SELECT * FROM blog ORDER BY ?; 4. 你不能让占位符 ? 代替任何其他SQL语法,如:SELECT EXTRACT( ? FROM datetime_column) AS variable_datetime_element FROM blog; 四、总结 sql注入,可以从多方面来进行防范,在可能的情况下,如果数据库需要存储多字节字符,建议数据库的编码方式尽量采用UTF8;另外,在查询数据库的逻辑实现过程中,我们要加强对于语句编写方面的一些安全意识,如,对于整型数值进行强制性的类型校验等;在解决方案上,建议采用 PDO 方式来实现相关的数据库操作逻辑。 而对于另外几种攻击方式,区别在于传送攻击的方式不同,原理还是一样,所以不再赘叙。 附件: 测试实验文件:http://pan.baidu.com/share/link?shareid=963562568&uk=1090915711
附件列表
相关文章推荐
- mysql防注入攻击解决办法
- Java应用中的SQL依赖注入攻击和防范
- PHP MYSQL注入攻击需要预防7个要点
- MySQL注射攻击与防范详解
- Java Web 防范 SQL 注入攻击
- MySQL 注射攻击与防范详解
- windows 2003防范脚本注入攻击
- 遭遇一次MySQL猜解注入攻击
- Php+Mysql注入攻击详解
- MySQL注入攻击与防御
- 斩断注入黑手 防范IE漏洞攻击
- 黑客知识:注入程序带来的攻击及防范
- mysql注入攻击扫描备忘;
- MySQL注射攻击与防范详解
- MySQL注射攻击与防范详解
- php mysql注入攻击解决方案
- 转: MSSQL 注入攻击的防范
- PHP基础----PHP 与 MySQL----28用户数据添加与防 SQL 注入攻击
- MySQL 及 SQL 注入与防范方法
- 对php+mysql的注入攻击