【发布时间】:2010-10-07 08:27:07
【问题描述】:
防止 MySQL 注入的最佳方法是什么?我应该注意哪些弱点?
我知道它是什么,但我真的不知道我可能有多脆弱。尽管我已采取(我认为的)措施来保护自己和我的数据库。
有什么可靠的方法可以阻止某人吗?
顺便说一句...我用 PHP 编写:)
【问题讨论】:
标签: php mysql database sql-injection
防止 MySQL 注入的最佳方法是什么?我应该注意哪些弱点?
我知道它是什么,但我真的不知道我可能有多脆弱。尽管我已采取(我认为的)措施来保护自己和我的数据库。
有什么可靠的方法可以阻止某人吗?
顺便说一句...我用 PHP 编写:)
【问题讨论】:
标签: php mysql database sql-injection
经过一些实验,我为完全干净的 SQL 注入创建了两个函数。与准备好的语句搭配使用,效果完美。
// Cleanup outer SQL
protected static function escapeOuter( string $s ): string {
return preg_replace(
['/(\/\*\s*\w*\s*(?!.\/\*))/si', '/(\-\-\s*\w*\s*(?!.\-\-))/si', '/(or\s*\w*\s*=\s*\w(?!.*or)|\|\|\s*\w*\s*=\s*\w(?!.\|\|))/si'],
[';', ';', ''],
str_replace(
[ '+--', '--+', '"', "\x1a", '%', 'qq ', '--', '/*!',],
[ '', ';', '"', '\\Z', "\%", '--', '/*!'],
trim( $s )
)
);
}
// Cleanup inner SQL
protected static function innerEscape( string $v ): string {
// Secure stage means that inner SQL clauses fixed to be secure
$secureStage = str_ireplace(
['ASCII', 'UNION', ' OR ', '||', ' AND ', '&&', ' ON ', "'", '+--', '--+', 'qq', '"', '--', '/*!', ],
['', '', ' or ', ' || ', ' and ', ' && ', ' on ', '\'', '', ';', '', '"', '--', '/*!'],
addslashes(
htmlspecialchars( $v )
)
);
// Not available to use built in escape future when DB connection not established
if( isset( self::$dbx_lnk[ 1 ] ) ) {
if( (bool)self::$dbx_lnk[ 1 ]['CONNECTION'] ) {
return mysqli_real_escape_string( self::$dbx_lnk[ 0 ], $secureStage );
}
else {
return $secureStage;
}
}
else {
return $secureStage;
}
}
这个函数是我自己DataBase driver的一部分。
例如,您必须使用 innerEscape 未来来清理字段值,而使用 escapeOuter 未来来清理完整的 MySQL 查询。过滤后必须使用 PDO 或 MySQLi 的预处理语句。
【讨论】:
这似乎是常识,但我有一段时间被绊倒了。
编码 htmlentities() 和转义 mysql_real_escape_string() 之间存在差异。我认为它们是可以互换的。然而,没有......常识会告诉你。 :) 通常最好同时应用它们,例如先编码,然后转义。
然后,当拉出数据时,反向过程,取消转义(如果需要)然后取消编码。请注意,具体执行(和反转)步骤的方式将避免很多麻烦和双重逃避的麻烦。
【讨论】:
不要相信任何人!
根据数据类型清理所有输入——filter_var() 或正则表达式或in_array() 的有效值或混合策略。
“输入”是指您不直接控制的任何输入源——不仅仅是表单!
对您从$_GET、$_POST、$_SESSION、$_COOKIE 返回的任何东西进行消毒——任何可能被污染的东西。
与
使用准备好的语句
【讨论】:
在我尝试在任何代码(MySQL 查询、数据显示等)中使用它之前,我在所有输入上都使用了这个 PHP 函数。它可能还不完整,但它应该会阻止所有入侵系统的基本尝试:
//$linkID is the link ID of the connection to the MySQL database
function clean_input($input)
{
GLOBAL $linkID;
if(get_magic_quotes_gpc())
{
//Remove slashes that were used to escape characters in post.
$input = stripslashes($input);
}
//Remove ALL HTML tags to prevent XSS and abuse of the system.
$input = strip_tags($input);
//Escape the string for insertion into a MySQL query, and return it.
return mysql_real_escape_string($input,$linkID);
}
【讨论】:
如果您没有使用为您提供清理工具的框架 PHP 有一个内置的字符串转义器,您应该从那里开始。您可以在 within the PHP docs for mysql real escape string 上找到文档。如果您查看示例 3,您会很好地了解可以遵循的基础知识。
我遵循的另一种方法是确保在适当的位置转换变量。例如,如果我希望用户的输入是整数,我将执行以下操作:
$age = (int)$age;
此外,如果一列应该被限制为一个或两个值(例如性别列),请确保在将其放入数据库之前在 PHP 中强制执行。
【讨论】:
您可能遇到问题的迹象是直接接受用户输入并将其放入您的 SQL 命令中。
例如,您询问他们的用户名。如果你拿着它然后简单地说
"Select * From Users Where Username = '$USERNAME';"
然后用户可以添加“JOE'; Drop Table...”等等。
在 perl 中你可以这样说
my $sth2 = $dbh->prepare("Insert Into HostList (HostName,PollTime,Status) values (?,?,?);");
$sth2->execute($Hostname,$myDate,$Status);
execute 方法然后会寻找上述漏洞利用并正确转义。
【讨论】:
您必须清理所有输入。 如何做到这一点取决于您使用的编程语言和/或框架。
编辑:
如果您使用 php,您正在寻找的函数是 mysql_real_escape_string($string)。您应该在从客户端收到的所有应该进入数据库的内容上使用它。
【讨论】: