文章主要以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";
}
?>
函数转义 SQL 语句中使用的字符串中的特殊字符。
下列字符受影响:
函数用于检测变量是否为数字或数字字符串。
函数语法 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";
这个方法的局限在于只能接收数字型参数,如果想使用字符型参数则不能使用这个函数。
函数执行一个正则表达式的搜索和替换。
函数语法 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全名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攻击者没有一点机会。我们执行一下看下结果。
我们给id赋值为 1 and 1=2 但发送到mysql的语句仍为select id,name,pass from user where id=:id,随后接收的id再单独发送至数据库。