如果用户输入未经修改就插入到SQL查询中,则应用程序很容易受到SQL注入的攻击,如下例所示:

$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;--')

可以采取什么措施防止这种情况发生?


当前回答

无论你最终使用的是什么,确保你的输入没有被magic_quotes或其他善意的垃圾破坏,如果有必要的话,通过条带斜杠或其他方式来清理它。

其他回答

我建议使用PDO(PHP数据对象)运行参数化SQL查询。

这不仅可以防止SQL注入,还可以加快查询速度。

而且,通过使用PDO而不是mysql_、mysqli_和pgsql_函数,可以使应用程序从数据库中抽象出一点,这是很少需要切换数据库提供程序的情况。

这个问题的简单替代方案可以通过在数据库本身中授予适当的权限来解决。例如:如果您使用的是MySQL数据库,则通过终端或提供的UI输入数据库,然后执行以下命令:

 GRANT SELECT, INSERT, DELETE ON database TO username@'localhost' IDENTIFIED BY 'password';

这将限制用户只能受限于指定的查询。删除删除权限,这样数据就永远不会从PHP页面发出的查询中删除。第二件事是刷新特权,以便MySQL刷新权限和更新。

FLUSH PRIVILEGES; 

有关刷新的详细信息。

要查看用户的当前权限,请启动以下查询。

select * from mysql.user where User='username';

了解更多有关GRANT的信息。

从安全角度来看,我倾向于存储过程(MySQL从5.0开始就支持存储过程),其优点是-

大多数数据库(包括MySQL)允许将用户访问限制为执行存储过程。细粒度安全访问控制有助于防止特权攻击升级。这防止了受损的应用程序能够直接针对数据库运行SQL。它们从应用程序中提取原始SQL查询,因此应用程序可以获得的数据库结构信息较少。这使得人们更难理解数据库的底层结构并设计合适的攻击。它们只接受参数,因此参数化查询的优势就在这里。当然,IMO仍然需要清理输入,尤其是在存储过程中使用动态SQL时。

缺点是-

它们(存储过程)很难维护,而且往往会很快繁殖。这使得管理它们成为一个问题。它们不太适合动态查询——若构建它们是为了接受动态代码作为参数,那个么许多优点就被否定了。

一个好主意是使用像Idiorm这样的对象关系映射器:

$user = ORM::for_table('user')
->where_equal('username', 'j4mie')
->find_one();

$user->first_name = 'Jamie';
$user->save();

$tweets = ORM::for_table('tweet')
    ->select('tweet.*')
    ->join('user', array(
        'user.id', '=', 'tweet.user_id'
    ))
    ->where_equal('user.username', 'j4mie')
    ->find_many();

foreach ($tweets as $tweet) {
    echo $tweet->text;
}

它不仅可以避免SQL注入,还可以避免语法错误!它还支持具有方法链接的模型集合,以一次过滤或将操作应用于多个结果和多个连接。

无论你最终使用的是什么,确保你的输入没有被magic_quotes或其他善意的垃圾破坏,如果有必要的话,通过条带斜杠或其他方式来清理它。