论sql注入的攻与防

来源:互联网 发布:淘宝买烟丝暗号 编辑:程序博客网 时间:2024/04/30 03:26

论sql注入的攻与防

本文主要从实例出发来展示sql注入的攻受之道,啊,不对,攻守之道。

攻击篇

sql注入是恶意用户(都不想称之为黑客)通过url或者form向应用程序传递sql语句来攻击数据库的常用手段。我们可以从google或者baidu搜索inurl:php?id=, inurl:asp?id=出来一些传递id参数的网页,但是尽量别试,都是老实孩子,干嘛非拿人家的网站试。这个地方只是介绍了一些搜索引擎的小技巧,比如严格检索"keyword1 keyword2", 剔除检索中的一些结果keyword -keyword1, 站内检索site:www.xxx.com keyword,我去,扯的有点远了。
自己做一个网页测试。
下面以PHP+MySQL为例模拟一个sql注入。假设我们有一个url为xxx.php?id=xxx的页面:

<?php    $uid = $_GET['id'];    $sql = "SELECT * FROM user WHERE u_id=$uid";    $query = $mysqli->query($sql);    if (!!$query){        while(!!$row = $query->fetch_row()){            var_dump($row);            echo '<br />';        }    }else{        echo $mysqli->error;    }

下面我们开始测试:

#1 测试是否加入注入检查

命令行中输入urlphp?id=1',从页面的错误中我们能够得知数据库为MySQL

#2 查看MySQL基本信息

url:php?id=1 and 1=2 union select 1,2, concat(user(), 0x20, database(), 0x20, version()), 我们可以查看到当前mysql连接的user,host,版本号等。这条注入可能抛出字段数不相等的错误,我们可以通过增删1,2来变化字段数,直到查出结果。

#3 查出所有表名

php?id=1 and 1=2 union select 1,2, group_concat(distinct table_name) from information_schema.tables where table_schema=database() --

#4 列出表中字段

php?id=1 and 1=2 union select 1,2 group_concat(distinct column_name) from information_schema.columns where table_name=tableName--
tableName为16进制数,需要转换一下再写到url中。

#5 将查询数据输出到文件

php?id=1 and 1=2 union select 1,2 name, password from admin into outfile 'D:\db.txt'

注入的招数还有好些,不想往下写了,这节主要是为了展示一些注入的危害性,千万不能写成注入的教程,抑制住自己邪恶的想法。重点在下面的防守篇。

防守篇

NBA教练菲尔.杰克逊曾经说过这样一句话:“进攻赢得观众,防守赢得总冠军”,可见防守对于一个志在总冠军的球队是如何的重要。如果还记得你曾经查询过的如家、七天开房记录,防守对于网站的重要性,就不需要我再赘述了,更何况sql注入造成的破坏,不仅仅是泄漏用户数据而已。
如何防守?
NBA的最佳防守队员是有共性的,一般都能跑、能跳、能盖帽。网站防范sql注入攻击也是有招数可循的。可千防万防都逃不过一句话:
永远不要相信用户输入
像攻击篇中从$_POST中取出数据,直接用到数据库查询中的事,千万别再干了。可我从$_GET,$_POST中取出数据应该怎样处理呢?

检查url

配置nginx,检查url:

if ($request_url ~* (select|insert|update|delete|\'|\*|\/\*|\.\.\/||union|into|load_file|outfile|\-\-\s)){    rewrite ^(.*)$ /malicious.php break;}

这样带有非法字符的url都会被重定向到malicious.php,在malicious.php,我们可以显示非法用户的ip地址,访问时间等,说一些狠话来震慑一下。
但是,这样只能过滤url中的参数,post方法中的数据不能过滤,另外上面的正则表达式中过滤的可能不全。

在PHP中过滤参数

<?php    $uid = $_POST['id'];    if (eregi('select|insert|update|delete|\'|\*|\/\*|\.\.\/||union|into|load_file|outfile|\-\-\s', $uid)){        header('Location:/malicious.php');    }else{    }

强制类型转换

对参数做强制类型转换。

<?php    $str = '1 and 1=2';    echo 'str: '.$str;    $str1 = intval($str);    echo '<br />after int cast: '.$str1;    $str2 = floatval($strs);    echo '<br />after float cast: '.$str2;

输入结果为:

str:1 and 1=2aster int cast: 1after float cast: 1  

从结果我们可以看出,字符串中的非法字符被过滤掉。

escape

在PHP manual的mysqli::query方法中,对sql语句定义是这样的Data inside the query should be escaped。意思是,我们在query之前需要对参数escape:

$uid = $_GET[id];//下面的两个escpe,一个是面向过程,一个是面向对象$uid = mysqli_real_escape_string($uid);$uid = mysqli->real_escape_string($uid);$sql = "SELECT * FROM user where u_id=$uid";$mysqli->query($sql);

prepared stmt, 参数绑定

$uid = $_GET['id'];$sql = 'SELECT * FROM user WHERE u_id=?';if($stmt = mysqli->prepare($sql)){    $stmt->bind_param('d', $uid);    $stmt->execute();    $stmt->bind_result($user);    var_dump($user);}

使用ORM工具

使用ORM工具也可以防范sql注入攻击。
在知乎看到有人说low逼的程序猿才会自己写sql语句,有逼格的攻城狮都用ORM。用不用ORM是个人选择,没必要个人攻击。

暂时写这些吧,怪费脑子的。

0 0