如果用户输入未经修改就插入到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()。)重要的防止SQL注入的最佳方法是使用Prepared语句而不是转义,正如公认的答案所示。有Aura.Sql和EasyDB这样的库可以让开发人员更容易地使用准备好的语句。若要了解更多有关为什么准备好的语句更善于停止SQL注入的信息,请参阅此mysql_real_ascape_string()旁路以及最近修复的WordPress中的Unicode SQL注入漏洞。
注入预防-mysql_real_ascape_string()
PHP有一个专门制作的函数来防止这些攻击。您所需要做的就是使用一个函数,mysql_real_aescape_string。
mysql_real_aescape_string获取一个将在mysql查询中使用的字符串,并返回同一个字符串,所有SQL注入尝试都安全逃脱。基本上,它会将用户可能输入的那些麻烦的引号(')替换为MySQL安全的替代品,即转义引号“”。
注意:您必须连接到数据库才能使用此功能!
//连接到MySQL
$name_bad = "' OR 1'";
$name_bad = mysql_real_escape_string($name_bad);
$query_bad = "SELECT * FROM customers WHERE username = '$name_bad'";
echo "Escaped Bad Injection: <br />" . $query_bad . "<br />";
$name_evil = "'; DELETE FROM customers WHERE 1 or username = '";
$name_evil = mysql_real_escape_string($name_evil);
$query_evil = "SELECT * FROM customers WHERE username = '$name_evil'";
echo "Escaped Evil Injection: <br />" . $query_evil;
您可以在MySQL-SQL注入预防中找到更多详细信息。
要使用参数化查询,需要使用Mysqli或PDO。要用mysqli重写示例,我们需要以下内容。
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("server", "username", "password", "database_name");
$variable = $_POST["user-input"];
$stmt = $mysqli->prepare("INSERT INTO table (column) VALUES (?)");
// "s" means the database expects a string
$stmt->bind_param("s", $variable);
$stmt->execute();
你想在那里读到的关键函数是mysqli::prepare。
此外,正如其他人所建议的,您可能会发现使用PDO之类的东西来提升抽象层是有用的/更容易的。
请注意,您询问的案例相当简单,更复杂的案例可能需要更复杂的方法。特别地:
如果您希望根据用户输入更改SQL的结构,参数化查询将不会有帮助,并且mysql_real_ascape_string不包含所需的转义。在这种情况下,最好通过白名单传递用户的输入,以确保只允许通过“安全”值。
安全警告:此答案不符合安全最佳实践。转义不足以防止SQL注入,请改用准备好的语句。使用以下概述的策略,风险自负。(此外,在PHP7中删除了mysql_real_ascape_string()。)不推荐使用警告:mysql扩展目前不推荐使用。我们建议使用PDO扩展
我使用三种不同的方法来防止我的web应用程序容易受到SQL注入的攻击。
使用mysql_real_aescape_string(),这是PHP中的一个预定义函数,此代码为以下字符添加反斜杠:\x00、\n、\r、\、'、“和\x1a。将输入值作为参数传递,以最大限度地减少SQL注入的机会。最先进的方法是使用PDO。
我希望这对你有帮助。
考虑以下查询:
$iId=mysql_real_ascape_string(“1或1=1”);$sSql=“SELECT*FROM table WHERE id=$iId”;
mysql_real_aescape_string()在这里不起保护作用。如果在查询中的变量周围使用单引号(“”),则可以防止这种情况发生。下面是一个解决方案:
$iId=(int)mysql_real_aescape_string(“1或1=1”);$sSql=“SELECT*FROM table WHERE id=$iId”;
这个问题有一些很好的答案。
我建议,使用PDO是最好的选择。
编辑:
自PHP 5.5.0起,mysql_real_aescape_string()已被弃用。使用mysqli或PDO。
mysql_real_aescape_string()的替代方法是
string mysqli_real_escape_string ( mysqli $link , string $escapestr )
例子:
$iId = $mysqli->real_escape_string("1 OR 1=1");
$mysqli->query("SELECT * FROM table WHERE id = $iId");