PHP mysql_query SQL 注入预防措施

更新日期: 2017-02-24 阅读次数: 10800 分类: 安全

目前维护的一套 ecshop 系统,由于使用的是 PHP 5.2 加之历史遗留代码安全意识淡薄,所以存在诸多 SQL 注入的隐患(大量拼接 SQL 字符串的行为)。而我入门 PHP 是通过 Laravel 官方教程开始的,没有写过原生 PHP SQL 查询,对如何规避 SQL 注入一无所知。

首先看一下 PHP 官方文档

mysql_query — Send a MySQL query

This extension was deprecated in PHP 5.5.0, and it was removed in PHP 7.0.0. Instead, the MySQLi or PDO_MySQL extension should be used. See also MySQL: choosing an API guide and related FAQ for more information. Alternatives to this function include: mysqli_query() PDO::query()

原来 mysql_query 已经被 PHP 7 所抛弃,甚至 PHP 5.6 都不支持。但是在将 ecshop 改造支持 PHP 7 之前,还是有必要了解一下 PHP 5.2 下如何规避 SQL 注入。

使用 sprintf 规避拼接 SQL 字符串

$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
            mysql_real_escape_string($user),
            mysql_real_escape_string($password));

sprintf - Returns a string produced according to the formatting string format.

同时使用 mysql_real_escape_string 将单引号转义。

规避 SQL LIKE 引起的注入

mysql_real_escape_string() does not escape % and _. These are wildcards in MySQL if combined with LIKE, GRANT, or REVOKE.

使用 mysql_real_escape_string 无法转义 %, 所以在 LIKE 操作时,依然会留有安全隐患。正确的做法是

$search = mysql_real_escape_string($search);
$search = addcslashes($search, "%_");

函数说明

string addcslashes ( string $str , string $charlist ) - Returns a string with backslashes before characters that are listed in charlist parameter.

封装,让使用更简单

把这两种情况封装成了一个函数

function sql_escape($param, $is_like_param = false) {
	$param = mysql_real_escape_string($param);
	if ($is_like_param) {
		$param = addcslashes($param, "%_");
	}

	return $param;
}

参考

  • http://php.net/manual/en/function.mysql-real-escape-string.php
  • http://stackoverflow.com/questions/3683746/escaping-mysql-wild-cards
  • http://www.webappsec.org/projects/articles/091007.txt
  • http://stackoverflow.com/questions/2190737/what-is-the-difference-between-mysql-mysqli-and-pdo
  • PDO 教程
  • 淺談 PHP-MySQL, PHP-MySQLi, PDO 的差異

关于作者 🌱

我是来自山东烟台的一名开发者,有敢兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式