sql注入的代码修复

文章主要以php环境讲述sql注入的修复,从简单到复杂,当然网上也有相应的绕过方法。首先我们写一个存在sql注入的php文件。

";
echo ($query)."
"; $result = mysqli_query ($con,$query); if (mysqli_num_rows($result) > 0) { echo "查询结果为:
"; while($row = mysqli_fetch_assoc($result)) { echo "id:" . $row["id"]."
", "username:" . $row["name"]."
", "password " . $row["pass"]. "
"; } } else { echo "no information"; } ?>

mysqli_real_escape_string()

函数转义 SQL 语句中使用的字符串中的特殊字符。
下列字符受影响:

  • \
  • "
  • \x00
  • \n
  • \r
    其实实际过程中,主要还是过滤前三个字符,函数语法如下:mysqli_real_escape_string($ con,$ id);
    $con是数据库连接参数,对应的php语句为:
    $con = mysqli_connect(“localhost”,“root”,“root”,“db”);
    id为接受的参数,也可以是字符串"str"。
    我们将函数加在获取id之后 $ id = mysqli_real_escape_string($ con,$id);
    我们在执行一下看下效果 '被转换成 ’ sql查询错误
    sql注入的代码修复_第1张图片

is_numeric()

函数用于检测变量是否为数字或数字字符串。
函数语法 is_numeric( $id ) id为接收的参数也可为字符串
该函数可以基本过滤掉一般的注入语句,如果不是数字型则不带入查询直接结束。

if(is_numeric( $id )) {
$query = "select id,name, pass from user where id = $id";
echo "执行的sql语句为:
"; echo ($query)."
"; $result = mysqli_query ($con,$query); if (mysqli_num_rows($result) > 0) { echo "查询结果为:
"; while($row = mysqli_fetch_assoc($result)) { echo "id:" . $row["id"]."
", "username:" . $row["name"]."
", "password " . $row["pass"]. "
"; } } else echo "no information";

这个方法的局限在于只能接收数字型参数,如果想使用字符型参数则不能使用这个函数。

preg_replace()

函数执行一个正则表达式的搜索和替换。
函数语法 echo preg_replace (‘a’,‘b’,‘c’) 函数一个三个变量 第一个a是匹配的内容,b是要转换后的内容,c为转换的目标。
通俗一点说就是匹配到就替换,c中如果有包含a内容的字符串,就将其转换成b。下面是过滤一些危险语句的正则替换。

$pregs = '/select|insert|update|CR|document|LF|eval|delete|script|alert|\'|\/\*|\#|\--|\ --|\/|\*|\-|\+|\=|\~|\*@|\*!|\$|\%|\^|\&|\(|\)|\/|\/\/|\.\.\/|\.\/|union|into|load_file|outfile/';

PDO

PDO全名PHP Data Object
PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口。
PDO 提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。
PDO可以说是基本杜绝了sql注入,因为它将查询语句与接受的参数分离开来,哪怕输入恶意的sql查询语句,也起不到查询作用。
使用PDO访问MySQL数据库时,真正的real prepared statements 默认情况下是不使用的。为了解决这个问题,你必须禁用 prepared statements的仿真效果。下面是使用PDO创建链接的例子:

$pdo=new PDO("mysql:host=localhost;dbname=db","user","pass");
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

这行代码极其重要,如果没有禁用prepared statements的仿真效果,本地就会将查询的sql语句模板和经过本地转义的参数id 拼接然后发送到mysql进行查询,这还会导致sql注入。
防范sql注入通过预处理的一些方式以及bindParameter()方法绑定参数来防止SQL注入,本文主要举例bindParmeter()方法

setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$query = "select id,name, pass from user where id = :id";
echo "执行的sql语句为:
"; echo ($query)."
"; $stmt=$pdo->prepare($query); $stmt->bindParam(":id",$id,PDO::PARAM_STR); $stmt->execute(); $row = $stmt->fetch(); if( $stmt->rowCount() == 1 ) { echo "查询结果为:
"; $id=$row['id']; $user=$row['name']; $pass=$row['pass']; echo 'id:'.$id.'
',"name:".$user."
","pass:".$pass."
";} else echo 'no information'; ?>

上面这段代码就可以防范sql注入。为什么呢?
当调用 prepare() 时,查询语句已经发送给了数据库服务器,此时只有查询模板中的:id 发送过去,没有用户提交的数据id;当调用到 execute()时,用户提交过来的值才会传送给数据库,他们是分开传送的,两者独立的,SQL攻击者没有一点机会。我们执行一下看下结果。
sql注入的代码修复_第2张图片
我们给id赋值为 1 and 1=2 但发送到mysql的语句仍为select id,name,pass from user where id=:id,随后接收的id再单独发送至数据库。

你可能感兴趣的:(漏洞修复)