SQL注入实例( PHP + mysql )

SQL注入的产生一般是由:开发人员在编写过程中未对用户输入参数做处理,直接拼接SQL,导致数据库被篡改。

下面的Demo演示的是“恶意用户利用漏洞删除mysql数据”

<?php
//原有的sql模块,不安全的,抛弃
function sql($sql){
  /*
  * 这是一个为了使用方便而编写的sql方法。
  * 所有select开头的sql返回查询结果,
  * 所有非select开头的sql返回受影响的行数。
  */    

    $ip="***";
    $port=3306;
    $username="***";
    $password="***";
    $database="***";
    $return = 0;
    //创建PDO对象
    $dsn = "mysql:host=$ip;dbname=$database;port=$port;charset=utf8";
    if(preg_match("/^[iIuUdDsS][nNpPeE][sSdDlL][eEaA][rRtTcC][tTeE]/is",$sql)){
        try{
                        $options = array(
                          PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, //默认是PDO::ERRMODE_SILENT, 0, (忽略错误模式)
                          PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // 默认是PDO::FETCH_BOTH, 4
                        );
                        $pdo = new PDO($dsn, $username, $password, $options);
                        if (preg_match("/^[sS]/is",$sql)) {
                          //使用query
                          $stmt = $pdo->query($sql); //返回一个PDOStatement对象
                          $return = $stmt->fetchAll(); //获取所有
                          //$return = $stmt->rowCount(); //记录数
                        }else{
                          $return = $pdo->exec($sql); //返回受影响的行数
                          //$return = $pdo->lastInsertId();//返回修改的ID
                        }
                        $pdo = null;
                }catch(Exception $e){
                    $return = $e->getMessage();
                }
    }
    return $return;
}



/*
* Sql注入Demo,这是存在风险的实力:
*/
$k  = $_GET['k'];
$v  = $_GET['v'];
$i  = file_get_contents('php://input');
if( strlen($k)>0 && ((strlen($v)>0 && count($_GET)==2)||( strlen($i)>0 && count($_GET)==1) )){ 
    $v = strlen($v) > 0 ? $v : $i;
    echo sql("insert into kv(k,v)values('$k','$v');"); //没有使用预编译
    exit();
}

?>

 

 恶意用户访问:

1 curl "***.com/1.php?k=sql注入" -d "test');delete from kv;"

结果:kv表数据被全部删除!

MySQL [***_db]> select * from kv;
Empty set (0.04 sec)

MySQL [***_db]> 

 

解决方法:通过PHP prepare预编译sql

代码如下:

<?php

//进行预编译的sql方法
function ssql($sql,$arr=[],$json=false){
        $ip="***";
        $port=3306;
        $username="***";
        $password="***";
        $database="***";
        $dsn = "mysql:host=$ip;dbname=$database;port=$port;charset=utf8";
        $return = 0;

        if(preg_match("/^[iIuUdDsS][nNpPeE][sSdDlL][eEaA][rRtTcC][tTeE]/is",$sql)){
                try{
                        $options = array(
                                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, //默认是PDO::ERRMODE_SILENT, 0, (忽略错误模式)
                                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // 默认是PDO::FETCH_BOTH, 4
                        );
                        $pdo = new PDO($dsn, $username, $password, $options);//创建PDO对象
                        $stmt = $pdo->prepare($sql);//2)使用prepare预处理
                        $precute = $stmt->execute($arr);  //执行一条预处理语句 .成功时返回 TRUE, 失败时返回 FALSE 
                        if($precute){
                                if( preg_match("/^[sS]/is",$sql) ) {
                                        $sqlData = $stmt->fetchAll();
                                }else{
                                        $sqlData = $stmt->rowCount(); //成功数
                                }
                                if($json){
                                        $return = json_encode($sqlData,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);//JSON_PRETTY_PRINT|
                                }
                        }
                        $pdo = null;
                }catch(Exception $e){
                }
        }
    return $return;
}



/*
* 这是被测代码,使用预编译的sql方法
*/
$k  = $_GET['k'];
$v  = $_GET['v'];
$i  = file_get_contents('php://input');
if( strlen($k)>0 && ((strlen($v)>0 && count($_GET)==2)||( strlen($i)>0 && count($_GET)==1) )){ 
    $v = strlen($v) > 0 ? $v : $i;
    echo ssql("insert into kv(k,v)values(?,?);",[$k,$v]);
    exit();
}
?>

 

 恶意用户访问:

1 curl "***.com/1.php?k=sql注入" -d "test');delete from kv;"

结果:直接存入data,没有数据被删除。

MySQL [***_db]> select * from kv;
+----+------+-----------+------------------------+------+
| i | s | k | v | n |
+----+------+-----------+------------------------+------+
| 89 | NULL | sql注入 | test');delete from kv; | NULL |
+----+------+-----------+------------------------+------+
1 row in set (0.04 sec)

MySQL [***_db]>

 

上一篇:点击实现新增一行


下一篇:WebUploader 被 FormData 函数坑了,用了他的页面千万别定FormData变量