如果用户输入未经修改就插入到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;--')
可以采取什么措施防止这种情况发生?
不推荐的警告:这个答案的示例代码(与问题的示例代码一样)使用了PHP的MySQL扩展,该扩展在PHP 5.5.0中被弃用,在PHP 7.0.0中被完全删除。安全警告:此答案不符合安全最佳实践。转义不足以防止SQL注入,请改用准备好的语句。使用以下概述的策略,风险自负。(此外,在PHP7中删除了mysql_real_ascape_string()。)
参数化查询AND输入验证是一种方法。尽管使用了mysql_real_ascape_string(),但在许多情况下可能会发生SQL注入。
这些示例易受SQL注入攻击:
$offset = isset($_GET['o']) ? $_GET['o'] : 0;
$offset = mysql_real_escape_string($offset);
RunQuery("SELECT userid, username FROM sql_injection_test LIMIT $offset, 10");
or
$order = isset($_GET['o']) ? $_GET['o'] : 'userid';
$order = mysql_real_escape_string($order);
RunQuery("SELECT userid, username FROM sql_injection_test ORDER BY `$order`");
在这两种情况下,都不能使用“”来保护封装。
来源:意外的SQL注入(当转义不够时)
安全警告:此答案不符合安全最佳实践。转义不足以防止SQL注入,请改用准备好的语句。使用以下概述的策略,风险自负。(此外,在PHP7中删除了mysql_real_ascape_string()。)
警告:mysql扩展名此时被删除。我们建议使用PDO扩展
使用此PHP函数mysql_escape_string(),您可以快速获得良好的预防效果。
例如:
SELECT * FROM users WHERE name = '".mysql_escape_string($name_from_html_form)."'
mysql_escape_string-转义用于mysql_query的字符串
为了更好地预防,您可以在末尾添加。。。
wHERE 1=1 or LIMIT 1
最后你得到:
SELECT * FROM users WHERE name = '".mysql_escape_string($name_from_html_form)."' LIMIT 1
这个问题的简单替代方案可以通过在数据库本身中授予适当的权限来解决。例如:如果您使用的是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的信息。