我的问题是关于数据库连接和SQL注入的应用程序。我正在使用下面提供的代码成功连接到我的数据库。我想问一下:
foreach如何停止SQL注入?
是否有更好,更有效的方法来使连接更安全?
如果将dbconnect.php包含在另一个文件(例如global.php)中,而该连接又包含在实际使用数据库的主文件中,则该连接是否仍会工作并向我提供数据库中的有效数据?是吗
example_file.php:
<?php
//MySQL Database Connect
include './includes/dbconnect.php';
//This stops SQL Injection in POST vars
foreach ($_POST as $key => $value) {
$_POST[$key] = mysql_real_escape_string($value);
}
//This stops SQL Injection in GET vars
foreach ($_GET as $key => $value) {
$_GET[$key] = mysql_real_escape_string($value);
}
?>
dbconnect.php:
<?php
$con = mysql_connect("localhost","username","password");
if (!$con){ die('Could not connect: ' . mysql_error()); }
mysql_select_db("databasename", $con);
?>
非常感谢!
最佳答案
foreach如何停止SQL注入?
这真的非常重要,因此我要大声说出来,希望人们可以理解……
没有!
“为什么不呢?”,我听到你问。好吧,我年轻的padawan,是因为:
它只转义字符串
假设有一个网站,用户可以通过该网站查看他们的病历。为了使用户能够过滤与特定疾病相关的记录,可以允许其id
将疾病指定为查询参数:
http://www.example.com/health/fetchmyrecords.php?illness=123
开发人员首先在您的问题中应用foreach
循环,然后假定“ phe,我可以安全地进行SQL注入-不用担心!”,然后这样做:
$res = mysql_query("
SELECT *
FROM health_records
WHERE user = $_SESSION[uid]
AND illness = $_GET[illness]
");
while ($row = mysql_fetch_array($res)) print_r($row);
你看到问题了吗?考虑一下。
问题
假设有人请求以下URI:
http://www.example.com/health/fetchmyrecords.php?illness=123+OR+1
然后,MySQL将收到以下查询:
SELECT *
FROM health_records
WHERE user = 987
AND illness = 123 OR 1
SQL成功注入!在此特定示例中,注入是致命的,因为MySQL会将
WHERE
子句解析为:WHERE (user = 987 AND illness = 123) OR 1
…因此它实际上将返回数据库中每个用户的每条健康记录!
祝你好运,承受由此而产生的法律费用。有一个合理的猜测,就是您的业务将崩溃,您的个人财务将被破坏,您的房屋将被收回,您的妻子将离开您,您的孩子将不会与您说话并且您的猫会逃走!
解释(对于注射,不是您的猫的消失)是,一个人只能使用
mysql_real_escape_string()
转义字符串(线索在名称中)。它不能用于转义任何其他SQL令牌:not number literals;不是identifiers;当然不是SQL关键字或特殊字符。这些令牌必须以其他方式保护。因此,几乎不管其含义如何,都将每个接收到的变量任意转义几乎是不正确的。此外,结果仅在SQL中有用:如果您想将这些变量用于其他任何用途,数据将被杂乱无章,因此您实际上绝对不应该将结果存储回
$_GET
和$_POST
数组中。它只转义字符串
对于实际上是字符串的变量,仅应用
mysql_real_escape_string()
不一定会停止SQL注入。您还必须正确引用String Literals:字符串是字节或字符序列,用单引号(“
'
”)或双引号(“ "
”)字符括起来。但是,如果MySQL服务器处于
NO_BACKSLASH_ESCAPES
SQL模式,则mysql_real_escape_string()
不能安全地转义用于双引号的字符串。因此,为了安全起见,您必须:使用单引号文字;要么
明确设置其他一些SQL模式。
此外,在调用
mysql_real_escape_string()
之前,您必须首先告诉MySQL客户端库,服务器将使用哪种字符编码来解释此类字符串-通常通过调用mysql_set_charset()
(但是,有一些与编码相关的注入,即使这样做也不会失败如果您使用的是旧版客户端库)。有关更多详细信息,请参见SQL injection that gets around mysql_real_escape_string()。
加起来
使用最新的客户端库
致电
mysql_set_charset()
禁用
NO_BACKSLASH_ESCAPES
或使用单引号文字仅在字符串文字上使用
mysql_real_escape_string()
除了产生SQL之外,不要将结果用于任何其他用途
以其他方式使其他令牌安全
是否有更好,更有效的方法来使连接更安全?
是的,最肯定的是-已经有好几年了。实际上,以至于
mysql_real_escape_string()
确实应该被视为反模式。永远不要使用它。可悲的是,一个接一个的教程继续讲授这种可笑的过时和危险的构造SQL方法。他们中的许多人早已不存在了,因此原本写得不好可能是可以原谅的(但到现在为止,它们确实应该被更新,删除或忽略);但是,对于每一个推荐使用
mysql_real_escape_string()
的新课程或教程,上帝都会杀死一只小猫。有人会不会想到小猫?!“更好的方式”实际上有两个方面:
停止使用以
mysql_
为前缀的那些PHP函数。它们最初是在MySQL v3.23的PHP v2.0中引入的,自2006年以来未添加任何新功能。自2011年6月以来,该手册包含有关在新代码中使用它们的警告,并且在PHP v5.5中已正式弃用它们。 。PHP附带了两个非常好的现代替代方案:mysqli和PDO_MySQL-有关确定使用哪种方法的帮助,请参见MySQL: Choosing an API。
使用这些替代API之一,您可以对SQL语句进行参数化,以使文字值独立于语句本身传输到服务器:因此,服务器甚至都不会尝试解析这些文字值的SQL,无论它们包含的值如何。注入根本不可能从字面值发生(请注意,您仍然需要保护其他令牌,但这不是很常见的要求,并且不在此答案的范围之内)。
见How can I prevent SQL injection in PHP?
如果将dbconnect.php包含在另一个文件(例如global.php)中,而该连接又包含在实际使用数据库的主文件中,则该连接是否仍会工作并向我提供数据库中的有效数据?是吗
是。在大型项目中,包含文件包含更多文件是很常见的。
关于php - 它们如何工作:DB-Connect和SQL注入(inject)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23373888/