0

我的问题是关于数据库连接和 SQL 注入的应用。我正在使用下面提供的代码成功连接到我的数据库。我想问一下:

  1. foreach 如何停止 SQL 注入?
  2. 如果有更好更有效的方法使连接更安全?
  3. 如果将 dbconnect.php 包含在另一个文件(例如 global.php)中,连接是否仍然有效并为我提供来自数据库的有效数据,作为回报,该文件包含在实际使用数据库的主文件中是?

示例文件.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);

?>

非常感谢!

4

1 回答 1

4
  1. foreach 如何停止 SQL 注入?

    这真的重要,所以我要大声说出来,希望人们能理解……

    它没有!

    为什么不呢? ”,我听到你问。好吧,我年轻的学徒,那是因为:

    1. 它只转义字符串

      让我们想象一个网站,用户可以通过该网站查看他们的医疗记录。为了使用户能够过滤与特定疾病相关的记录,允许将疾病指定id为查询参数:

      http://www.example.com/health/fetchmyrecords.php?illness=123

      开发人员首先foreach在您的问题中应用循环,然后假设“唷,我可以安全地避免 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 标记:不是数字文字;不是标识符;当然不是 SQL 关键字或特殊字符。这些代币必须以其他方式保护。

      因此,无论其含义如何,任意转义每个接收到的变量几乎肯定是不正确的。此外,结果仅在 SQL 中有用:如果您想将这些变量用于其他任何事情,数据将被删除——因此您真的不应该将结果存储回$_GETand$_POST数组中。

    2. 它只转义字符串

      对于实际上是字符串的变量,仅仅应用mysql_real_escape_string()并不一定会停止 SQL 注入。您还必须正确引用String Literals

      字符串是由单引号 (“<code>'”) 或双引号 (“<code>”) 字符括起来的字节或字符序列。

      但是,如果 MySQL 服务器处于NO_BACKSLASH_ESCAPESSQL 模式,则mysql_real_escape_string()不会安全地转义字符串以在双引号内使用。因此,为了安全起见,您必须:

      • 使用单引号文字;或者

      • 显式设置一些其他 SQL 模式。

      此外,在调用之前,mysql_real_escape_string()必须首先告诉您的 MySQL 客户端库,服务器将使用哪种字符编码来解释这些字符串 - 通常通过调用mysql_set_charset()(但是,如果您使用的是一些与编码相关的注入,即使这样也不会失败。客户端库的真正旧版本)。

    有关更多详细信息,请参阅绕过 mysql_real_escape_string() 的 SQL 注入

    加起来 

    • 使用最新的客户端库

    • 称呼mysql_set_charset()

    • 要么 disable NO_BACKSLASH_ESCAPES,要么使用单引号文字

    • 仅用于mysql_real_escape_string()字符串文字

    • 除了生成 SQL 之外,不要将结果用于其他任何事情

    • 以其他方式使其他令牌安全


  2. 如果有更好更有效的方法使连接更安全?

    是的,肯定有——而且已经有好几年了。事实上,如此之多以至于mysql_real_escape_string()真的应该被认为是一种反模式。它不应该被使用。

    可悲的是,一个又一个教程继续教授这种可笑的过时且危险的 SQL 构造方法。他们中的许多人早在很久以前就已经存在了,所以他们最初写得不好可能是可以原谅的(但现在他们真的应该被更新、删除或忽略);然而,对于每一个推荐使用的新课程或教程mysql_real_escape_string(),上帝都会杀死一只小猫。不会有人想到小猫吗?!

    “更好的方法”实际上有两个方面:

    1. 停止使用那些以 . 为前缀的 PHP 函数mysql_。它们最初是在 PHP v2.0 for MySQL v3.23 中引入的,自 2006 年以来没有添加任何新功能。该手册包含自 2011 年 6 月以来在新代码中使用它们的警告,并且它们已在 PHP v5.5 中正式弃用.

      PHP 附带了两个非常好的现代替代方案:mysqliPDO_MySQL —请参阅MySQL:选择 API以帮助决定使用哪个。

    2. 使用这些替代 API 之一,您可以对 SQL 语句进行参数化,以便将文字值独立于语句本身传输到服务器:因此服务器甚至不会尝试为 SQL 解析这些文字值,而不管它们包含的值如何。注入根本不可能从文字值发生(请注意,您仍然需要保护其他令牌,但这是一个不太常见的要求,超出了此答案的范围)。

    请参阅如何防止 PHP 中的 SQL 注入?


  3. 如果将 dbconnect.php 包含在另一个文件(例如 global.php)中,连接是否仍然有效并为我提供来自数据库的有效数据,作为回报,该文件包含在实际使用数据库的主文件中是?

    是的。在大型项目中,包含文件包含更多文件是很常见的。

于 2014-04-30T09:39:05.140 回答