防止 MySQL 注入的最佳方法是什么?我应该注意哪些弱点?
我知道它是什么,但我真的不知道我可能有多脆弱。尽管我已经采取了(我认为的)措施来保护自己和我的数据库。
有什么可靠的方法可以阻止某人吗?
顺便说一句...我用 PHP 编写 :)
防止 MySQL 注入的最佳方法是什么?我应该注意哪些弱点?
我知道它是什么,但我真的不知道我可能有多脆弱。尽管我已经采取了(我认为的)措施来保护自己和我的数据库。
有什么可靠的方法可以阻止某人吗?
顺便说一句...我用 PHP 编写 :)
使用准备好的语句而不是混合语句和实际的有效负载数据。
看
您可能还对http://shiflett.org/articles/sql-injection和http://shiflett.org/blog/2007/sep/the-unexpected-sql-injection感兴趣
没有人相信!
根据数据类型清理所有输入 -filter_var()
或正则表达式或in_array()
有效值或混合策略。
“输入”是指您不直接控制的任何输入源——不仅仅是表单!
对你从$_GET
, $_POST
, $_SESSION
,回来的任何东西进行消毒$_COOKIE
——任何可能被污染的东西。
和
使用准备好的语句
您必须清理所有输入。如何做到这一点取决于您正在使用的编程语言和/或框架。
编辑:
如果您使用 php,您正在寻找的函数是 mysql_real_escape_string($string)。您应该在从客户端收到的应该进入数据库的所有内容上使用它。
如果你没有使用为你提供清理工具的框架 PHP 有一个内置的字符串转义器,你应该从那里开始。您可以在mysql real escape string 的 PHP 文档中找到相关文档。如果您查看示例三,您将对可以遵循的基础知识有一个很好的了解。
我遵循的另一种方法是确保在适当的地方转换变量。例如,如果我希望用户的输入是整数,我将执行以下操作:
$age = (int)$age;
此外,如果一列应该被限制为一个或两个值(例如性别列),请确保在将其放入数据库之前在 PHP 中强制执行此操作。
这似乎是常识,但我有一段时间被绊倒了。
编码 htmlentities()
和转义 是有区别的mysql_real_escape_string()
。我认为它们是可以互换的。然而,没有......常识会告诉你。:) 通常最好同时应用它们,例如先编码,然后转义。
然后在将数据拉出时反转该过程,取消转义(如果需要)然后取消编码。请注意,具体执行(和反转)步骤的方式将节省很多头痛和双重逃避的麻烦。
您可能遇到问题的迹象是直接接受用户输入并将其放入您的 SQL 命令中。
例如,您询问他们的用户名。如果你接受它然后简单地说
“从用户名中选择 * 用户名 = '$USERNAME';”
然后用户可以添加“JOE'; Drop Table...”等等。
在 perl 你可以说类似
my $sth2 = $dbh->prepare("Insert Into HostList (HostName,PollTime,Status) values (?,?,?);");
$sth2->execute($Hostname,$myDate,$Status);
然后,execute 方法将寻找上述漏洞利用并正确转义。
经过一些实验,我为完全干净的 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;
}
}
这个函数是我自己的数据库驱动程序的一部分。
例如,您必须使用 innerEscape 未来来清理字段值,而使用 escapeOuter 未来来清理完整的 MySQL 查询。过滤后,您必须使用 PDO 或 MySQLi 的准备好的语句。
在我尝试在任何代码(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);
}