Mysqli使用bind_param()防止SQL注入的原理

2023-09-05 15:33:51 浏览数 (2)

mysql sql注入 进阶

今天偶然看了一篇博文,说是一道php面试笔试题,原文如下:

请找出下面代码中的问题,修复并优化 <?php //批量注册用户,每次>100个。 //注册新用户,要求用户名与email不能与以前的重复。 $mysqli = new Mysqli($host, $user, $pass); for ($i=0; $i<count($_POST['user_info']); $i ) { $info = $_POST['user_info'][$i]; $re_1 = $mysqli->query("SELECT * FROM `demo` WHERE `uname`=$info['uname']"); $re_2 = $mysqli->query("SELECT * FROM `demo` WHERE `email`=$info['email']"); if (!$re_1 || !$re_2) { $mysqli->query("INSERT INTO `demo` (`uname`, `email`) VALUES('$info['email']', '$info['uname']')"); } }``` 答案: 基础:应该把count提到循环外。 基础:在字符串中拼装数组时候应该用 { 与 } 括起来。 基础:!$re_1 || $re_2应该是!$re_1 && !$re_2或者!($re_1 || $re_2)。 基础:insert语句的values部分两个字段顺序错了。 性能:uname与email两个语句应该拼装成一个OR语句。 性能:应该把所有SELECT拼装一个Sql,然后去除冲突的,再把剩余的通过批量插入的方式通过一条Sql插入。 性能:for应该该用foreach。 安全:参数没有过滤,但回答htmlspecialcharsaddslashes而非mysqli->real_escape_string的减分。 其它:query前没有USE database之类的操作,没有SET NAMES,能回答上来的比较细心。 其它:没有错误处理。

特意看了一下,是2013年的文章,所以不做过多评论,(mysqli连接少了一个参数,原文如此)。该题给出的答案并不太令人满意,通过这道题让我想到的是,应该怎么做才能尽量避免SQL注入?

使用mysqli批处理技术,bind_param()

代码语言:javascript复制
<?php
$mysqli = new mysqli('localhost', 'my_user', 'my_password', 'world');

/* check connection */
if (mysqli_connect_errno()) {
    printf("Connect failed: %sn", mysqli_connect_error());
    exit();
}

$stmt = $mysqli->prepare("INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
$stmt->bind_param('sssd', $code, $language, $official, $percent);

$code = 'DEU';
$language = 'Bavarian';
$official = "F";
$percent = 11.2;

/* execute prepared statement */
$stmt->execute();

printf("%d Row inserted.n", $stmt->affected_rows);

/* close statement and connection */
$stmt->close();

/* Clean up table CountryLanguage */
$mysqli->query("DELETE FROM CountryLanguage WHERE Language='Bavarian'");
printf("%d Row deleted.n", $mysqli->affected_rows);

/* close connection */
$mysqli->close();
?>

参数说明:

  • i corresponding variable has type integer 整数
  • d corresponding variable has type double 浮点型小数
  • s corresponding variable has type string 字符串
  • b corresponding variable is a blob and will be sent in packets 二进制包

原理说明:为什么bind_param()可以防止SQL注入?

  1. 使用了占位符(“?”):无论传多少值都是安全的,因为她已经被定义成一个参数,而非一条语句的部分;
  2. 预编译模式:在数据库层已经被编译成特定的执行方式,如select、insert等,不会因为后续的参数而改变执行方式;
  3. 内部自动转义特殊字符。

0 人点赞