- 学习MySQL
 - MySQL-主页
 - MySQL - 简介
 - MySQL-安装
 - MySQL - 管理
 - MySQL-PHP 语法
 - MySQL-连接
 - MySQL-创建数据库
 - MySQL - 删除数据库
 - MySQL - 选择数据库
 - MySQL - 数据类型
 - MySQL - 创建表
 - MySQL - 删除表
 - MySQL - 插入查询
 - MySQL - 选择查询
 - MySQL-Where 子句
 - MySQL - 更新查询
 - MySQL - 删除查询
 - MySQL - Like 子句
 - MySQL - 对结果进行排序
 - MySQL - 使用连接
 - MySQL - NULL 值
 - MySQL - 正则表达式
 - MySQL - 事务
 - MySQL - 更改命令
 - MySQL - 索引
 - MySQL - 临时表
 - MySQL - 克隆表
 - MySQL - 数据库信息
 - MySQL - 使用序列
 - MySQL - 处理重复项
 - MySQL - SQL 注入
 - MySQL - 数据库导出
 - MySQL - 数据库导入
 
- MySQL 有用资源
 - MySQL - 有用的函数
 - MySQL - 语句参考
 - MySQL - 快速指南
 - MySQL - 有用的资源
 - MySQL - 讨论
 
MySQL - 和 SQL 注入
如果您通过网页获取用户输入并将其插入 MySQL 数据库,则您可能会面临称为SQL 注入 的安全问题。本章将教您如何帮助防止这种情况发生,并帮助您保护脚本和 MySQL 语句的安全。
SQL 注入通常发生在您要求用户输入(例如他们的姓名)时,他们给您一条 MySQL 语句(而不是姓名),您将在不知不觉中在数据库上运行该语句。
永远不要相信用户提供的数据,仅在验证后处理该数据;通常,这是通过模式匹配来完成的。在以下示例中,用户名限制为字母数字字符加下划线,长度限制在 8 到 20 个字符之间 - 根据需要修改这些规则。
if (preg_match("/^\w{8,20}$/", $_GET['username'], $matches)) {
   $result = mysql_query("SELECT * FROM users WHERE username = $matches[0]");
} else  {
   echo "username not accepted";
}
为了演示这个问题,请考虑以下摘录。
// supposed input
$name = "Qadir'; DELETE FROM users;";
mysql_query("SELECT * FROM users WHERE name = '{$name}'");
该函数调用应该从用户表中检索一条记录,其中名称列与用户指定的名称相匹配。正常情况下,$name 仅包含字母数字字符,可能还包含空格。但在这里,通过向$name附加一个全新的查询,对数据库的调用变成了一场灾难。注入的 DELETE 查询会删除用户的所有记录。
幸运的是,如果您使用 MySQL,则mysql_query()函数不允许查询堆栈或在单个函数调用中执行多个查询。如果您尝试堆叠查询,则调用会失败。
然而,其他 PHP 数据库扩展(例如SQLite和PostgreSQL)很乐意执行堆叠查询,执行一个字符串中提供的所有查询,并产生严重的安全问题。
防止SQL注入
您可以在 PERL 和 PHP 等脚本语言中巧妙地处理所有转义字符。PHP 的 MySQL 扩展提供了函数mysql_real_escape_string()来转义 MySQL 特有的输入字符。
if (get_magic_quotes_gpc()) {
   $name = stripslashes($name);
}
$name = mysql_real_escape_string($name);
mysql_query("SELECT * FROM users WHERE name = '{$name}'");
LIKE 的困境
为了解决 LIKE 困境,自定义转义机制必须将用户提供的 % 和 _ 字符转换为文字。使用addcslashes(),该函数可让您指定要转义的字符范围。
$sub = addcslashes(mysql_real_escape_string("%something_"), "%_");
// $sub == \%something\_
mysql_query("SELECT * FROM messages WHERE subject LIKE '{$sub}%'");