【问题标题】:How they works: DB-Connect and SQL Injection?它们是如何工作的:DB-Connect 和 SQL 注入?
【发布时间】:2023-04-03 21:07:01
【问题描述】:

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

  1. foreach 如何停止 SQL 注入?
  2. 是否有更好更有效的方法使连接更安全?
  3. 如果将 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);

?>

非常感谢!

【问题讨论】:

    标签: php mysql include sql-injection dbconnection


    【解决方案1】:
    1. foreach 如何停止 SQL 注入?

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

      它没有!

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

      1. 它只转义字符串

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

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

        开发人员首先在您的问题中应用foreach 循环,然后假设“唷,我可以安全地避免 SQL 注入——不用担心!”,然后: p>

        $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 数组中。

      2. 它只转义字符串

        对于实际上是字符串的变量,仅仅应用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 以外的任何事情

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


    2. 是否有更好更有效的方式让连接更安全?

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

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

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

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

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

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

        李>

      How can I prevent SQL injection in PHP?


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

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

    【讨论】:

    • +1 来自我 - 很棒的作品! - 但是您引用的规范答案是否涵盖了所有这些?我想把这个问题作为一个重复的问题来结束,但我宁愿先听听你的看法。
    • 这个答案没有抓住重点。 “foreach”问题是一个魔术引号问题,已经在别处解释过。无需添加边缘案例——它们只会让读者感到困惑,让他认为他正在阅读一些重要的东西。另外,mysql_real_escape_string()也有注意事项,可以正常使用。第一个变体明显更好,更具可读性和有用性。
    • @halfer:我开始从两个稍微不同的角度来研究它,但他们可能已经迷失在细节上。首先,为什么转义 every 变量是错误的;其次,为什么覆盖$_POST$_GET 中的值是错误的。规范的“使用参数化语句”答案实际上只解决了 OP 的第二个问题,这就是为什么我对这部分给出了相对简短的答案。
    • @eggyal,好吧,这对我来说已经足够了。谢谢! (公平地说,另一个问题没有足够的猫)。
    • @YourCommonSense:修订版如何遗漏其中任何一点?它解决了标题为“问题”的框下的“foreach”问题,并在标题“总结”下提供了 mysql_real_escape_string() 可以安全使用的情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-03
    • 2018-06-21
    • 1970-01-01
    • 1970-01-01
    • 2011-01-05
    • 1970-01-01
    相关资源
    最近更新 更多