php - 它们如何工作:DB-Connect和SQL注入(inject)?

标签 php mysql include sql-injection dbconnection

我的问题是关于数据库连接和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附带了两个非常好的现代替代方案:mysqliPDO_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/

相关文章:

php - 内存使用从数据库导出到 PHP 中的 csv

javascript - 未插入数据库表的值

mysql - 如何优化 MySQL 选择查询或使其更快

c++ - 最佳编程实践,C++ header 和包含

php - PHPDoc 中的闭包语法

javascript - 当按下提交按钮而不是页面刷新时重新加载php脚本

php - laravel 5,我是否包含了太多库?

PHP:需要路径不适用于 cron 作业?

php - 发布到 Facebook Graph Api 很慢

PHP MySQL - 在 <Select></select> 表单上显示值