这段PHP代码安全吗?

这段PHP代码安全吗?,php,Php,简单问一下:下面的PHP代码安全吗?还有什么你认为我可以或应该补充的吗 $post = $_GET['post']; if(is_numeric($post)) { $post = mysql_real_escape_string($post); } else { die("NAUGHTY NAUGHTY"); } mysql_select_db("****", $*****); $co

简单问一下:下面的PHP代码安全吗?还有什么你认为我可以或应该补充的吗

    $post = $_GET['post'];

    if(is_numeric($post))
    {
        $post = mysql_real_escape_string($post);
    }
    else
    {
        die("NAUGHTY NAUGHTY");
    }

    mysql_select_db("****", $*****);

    $content = mysql_query("SELECT * FROM tbl_***** WHERE Id='" . $post . "'");

这有点粗糙,但我没有立即看到任何会给你带来严重问题的东西。您应该注意,根据文档,在
is\u numeric()
中接受十六进制表示法。您可能需要使用
is_int()
或强制转换它。为了清楚起见,我建议使用参数化查询:

$sql = sprintf("SELECT col1 
                FROM tbl 
                WHERE col2 = '%s'", mysql_real_escape_string($post));

在这种情况下,
$post
将被传入,因为
%s
的值是数值,对于十六进制数字,例如“0xFF”,它将返回true

编辑:要解决此问题,您可以执行以下操作:

sprintf('%d', mysql_real_escape_string($post, $conn));
//If $post is not an int, it will become 0 by sprintf

查看代码片段以了解更多信息。

在这种情况下,我想
是数字的
可以避免SQL注入(尽管您仍然可以中断SQL语句,参见Alex的回答)。但是,我真的认为你应该考虑使用参数化查询(AK.准备好的语句),因为:

  • 即使使用非数字类型的参数,它们也会保护您
  • 在添加更多参数时,不会有忘记输入的风险
  • 您的代码将更易于编写和阅读
  • 下面是一个示例(其中,
    $db
    是一个连接):

    有关PHP中参数化SQL语句的更多信息,请参阅:

      • 我觉得它看起来还可以


        在访问数据库时,我总是使用查询绑定,这样可以避免在忘记转义字符串时出现问题。

        您的想法是正确的,但是is\u numeric()可能无法按预期的方式工作

        尝试以下测试:

        <?php
        $tests = Array(
                "42", 
                1337, 
                "1e4", 
                "not numeric", 
                Array(), 
                9.1
                );
        
        foreach($tests as $element)
        {
            if(is_numeric($element))
            {
                echo "'{$element}' is numeric", PHP_EOL;
            }
            else
            {
                echo "'{$element}' is NOT numeric", PHP_EOL;
            }
        }
        ?>
        

        如果您正在查找通常称为数值的内容,则您的sql server可能无法理解1e4。从SQL注入的角度来看,您很好

        您没有将连接资源传递给mysql\u real\u escape\u string()(但您似乎是通过mysql\u select\u db()来传递连接资源的)。连接资源和其他东西一起存储连接字符集设置。
        不要在任何地方传递资源,或者(最好)总是传递资源,但不要让它比不通过混合两者来传递资源更糟糕

        我书中的“安全性”还包括代码是否可读、“可理解”以及是否做“直接”的事情。在本例中,您至少需要向我解释一下为什么要使用
        !当您在SELECT查询中将id视为字符串时,numeric->die
        根本不进行分支。我的反论点(如示例所示;在您的上下文中可能是错误的)是“为什么麻烦呢?SELECT不会返回非数字id的任何记录”,这将代码简化为

        if ( isset($_GET['post']) ) {
          $query = sprintf(
            "SELECT x,y,z FROM foo WHERE id='%s'",
            mysql_real_escape_string($_GET['post'], $mysqlconn) 
          );
           ...
        }
        
        这自动消除了您可能遇到的麻烦,因为is_numeric()的行为与您预期的不一样(如其他答案所述)

        编辑:关于使用
        die()。对于测试/示例代码来说这很好,但是在一个实时系统中,您几乎总是希望将控制权交还给周围的代码,而不是仅仅退出(这样您的应用程序就可以优雅地处理错误)。在开发阶段,您可能希望尽早退出或进行更多测试。在这种情况下,请看一看。
        您的示例可能符合断言的条件。如果断言被停用,它不会中断,但它可能会向开发人员提供更多信息,说明在传递非数字参数时,它为什么不能按预期(由另一个开发人员)工作。但是你必须小心区分必要的测试和断言;它们不是银弹。
        如果您觉得函数(?)是一个基本测试,那么您的函数(?)可能会返回false,抛出一个异常或一些东西来通知该条件。但对我来说,早死()是一条简单的出路,有点像一只不知所措的负鼠,“我不知道现在该怎么办。如果我装死,也许没人会注意到。”——)


        对准备好的语句的强制性提示:

        如果它传递了
        is\u numeric()
        ,那么不必对它执行
        mysql\u real\u escape\u string()
        。为什么不直接说
        $post=(int)$post
        ?@Skilldrick:如果数字超过一个int的大小,那可能会导致问题。@R.Bemrose这就是发生的事情,所以我选择使用is_numericToday真的是PHP安全日…啊,谢谢我会调查,有什么建议吗?我建议使用ctype_digit($string),如果$string的所有字符都是数字(regex模式[0-9]*),则返回true。如果您的id列不包含负值,这将特别好……我仍然建议将该测试全部删除,除非有解释说明为什么这是对
        id
        字段进行此类约束的最佳位置。函数(?)对表布局和数据插入代码中的
        id
        有自己的概念。这可能是必要的,或者是一个绝妙的想法,但对于那些在
        id
        成为数据库中更“轻松”的类型时必须删除它的人来说,这也可能是一个恼人的限制。测试附带一个(可能很小)价格标签,你必须解释为什么它值得。(虽然可能完全有效,但上下文很重要)对不起,什么是参数化查询?请检查使用prepare()定义$preparedStatement的行。参数化查询类似于带有占位符的SQL模板,您可以通过使用execute()将带有标记和值的数组传递给查询来填补空白。最后,使用fetchAll()获取数据。如果我没弄错的话,这是PDO。添加了一些链接,如果你选择这样做,这些链接应该可以帮助你开始学习——你真的应该;)我完全支持在这里使用事先准备好的语句(+1)。只是吹毛求疵:原始代码不受is_numeric()测试的sql注入的保护。通过使用real_escape_string()并将参数作为字符串文本传递给MySQL:
        Id='“$post.”“'42' is numeric
        '1337' is numeric
        '1e4' is numeric
        'not numeric' is NOT numeric
        'Array' is NOT numeric
        '9.1' is numeric
        
        if ( isset($_GET['post']) ) {
          $query = sprintf(
            "SELECT x,y,z FROM foo WHERE id='%s'",
            mysql_real_escape_string($_GET['post'], $mysqlconn) 
          );
           ...
        }