php前端部落,php防止SQL注入

如果不加修改就将用户输入插入到SQL查询中,那么应用程序很容易受到

9876214f73fbd4750c740839f21401b5.png

前言

首先,我们来看一个例子

$unsafe_variable = $_POST['user_input'];

mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')");

这是因为用户可以输入的值,可以变成一个drop table语句,例如:

INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')

那么我们如何避免这种情况呢?

解决思路

使用准备好的语句和参数化查询。这些SQL语句分别由数据库服务器发送和解析,与任何参数无关。这样攻击者就不可能注入恶意SQL。

有两种办法可以实现:

PDO

使用PDO(用于支持任何数据库的驱动程序)。

$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');

$stmt->execute([ 'name' => $name ]);

foreach ($stmt as $row) {

// Do something with $row

}

mysqli

如果是MySQL数据库,可以使用mysqli:

$stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?');

$stmt->bind_param('s', $name); // 's' specifies the variable type => 'string'

$stmt->execute();

$result = $stmt->get_result();

while ($row = $result->fetch_assoc()) {

// Do something with $row

}

如果要连接到MySQL以外的数据库,可以参考一个特定于驱动程序的第二个选项(例如,pg_prepare()和pg_execute(),用于PostgreSQL)。PDO是一个兼容性更好的选择。

正确的连接

注意,在使用PDO访问MySQL数据库时,默认情况下不使用real prepared语句。要解决这个问题,必须禁用模拟准备好的语句。使用PDO创建连接的一个例子是:

$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'password');

$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

在上面的例子中,错误模式并不是必须的,但是建议您添加它。这样,当出现错误时,脚本就不会因为致命错误而停止。并且它给开发人员机会来捕获任何作为pdoexception抛出的错误。

但是,必须执行的是第一个setAttribute()行,它告诉PDO禁用模拟的准备好的语句并使用真正的准备好的语句。这可以确保PHP在将语句和值发送到MySQL服务器之前不会对其进行解析(这使攻击者没有机会注入恶意SQL)。

虽然您可以在构造函数的选项中设置charset,但需要注意的是,PHP的“较老”版本(5.3.6之前)会忽略DSN中的charset参数。

解释

传递给prepare的SQL语句由数据库服务器解析和编译。通过指定参数(a ?或者一个命名参数,如:name(在上面的例子中),告诉数据库引擎要过滤到哪里。然后,当您调用execute时,准备好的语句与您指定的参数值相结合。

这里重要的一点是,参数值与编译后的语句相结合,而不是与SQL字符串相结合。SQL注入的工作原理是在脚本创建要发送到数据库的SQL时欺骗脚本包含恶意字符串。因此,通过将实际的SQL与参数分开发送,您可以限制以您不希望的方式结束的风险。

使用预处理语句的另一个好处是,如果在同一个会话中多次执行相同的语句,那么它只会被解析和编译一次,从而提高了一些速度。

那么如何插入数据呢,看下面这个例子(使用PDO):

$preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');

$preparedStatement->execute([ 'column' => $unsafeValue ]);

动态查询

虽然您仍然可以为查询参数使用准备好的语句,但是动态查询本身的结构不能参数化,某些查询特性也不能参数化。

对于这些特定的场景,最好的方法是使用一个白名单过滤器来限制可能的值。

// Value whitelist

// $dir can only be 'DESC', otherwise it will be 'ASC'

if (empty($dir) || $dir !== 'DESC') {

$dir = 'ASC';

}

原创文章,作者:犀牛前端部落,如若转载,请注明出处:https://www.pipipi.net/3358.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值