目前维护的一套 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 聊聊, 查看更多联系方式