是否将用户输入转换为足以清理它的整数?

问题描述 投票:4回答:8

引自this SO answer

提交的所有内容最初都被视为字符串,因此强制将已知数字数据转换为整数或浮点数使得清理快速且无痛。

这是我独立提出的一种快速和脏查询的清理方法(从数字ID中查找表中的名称);插入查询的唯一变量是ID,我知道ID应该大于零且小于255,所以我的清理如下(还有一点点验证):

$id = (int)$_REQUEST['id'];
if ($id < 1 || $id > 255) errmsg("Invalid ID specified!");
$name = $DB->query("SELECT name FROM items WHERE id=${id}")->fetch_all()[0][0];

这是否足以防止SQL注入攻击或基于用户指定的$id值的任何其他恶意攻击,还是仍然可以被利用?

注意:ID /名称不是“敏感”,所以如果某些输入无意中转换为“1”或其他有效的ID值,我不在乎。我只是想避免沿着Little Bobby Tables线上的滑稽动作。

php mysqli casting sql-injection
8个回答
5
投票

TL; DR答案是肯定的。当你施放到(int)时,除了整数之外你什么都得不到。

问题是你可能有一个用例会产生不良行为。我们来看看你的代码

$id = (int)$_REQUEST['id'];

现在,如果我们称之为

page.php?id=lolsqlinjection

然后$id的值是0(默认情况下所有字符串都转换为0)。所以这很安全。但是你可能有一个用例,其中0是一个特例或另一个记录。这就是准备好的语句往往被认为是优越的原因(显示MySQLi但你也可以用PDO做到这一点)

$prep = $DB->prepare("SELECT name FROM items WHERE id=?");
$prep->bind_param('i', $_REQUEST['id']);
$prep->execute();

这样做是告诉你的DB你想要与输入匹配的记录。因此,通过我的SQL注入,MySQL现在正在寻找一个整数id为“lolsqlinjection”的项目。没有这样的记录。因此,我们避免任何潜在的边缘情况,其中0将是有效的输入。


2
投票

我不得不初始化,准备,绑定,执行和获取所有内容,以便从单个结果中获取单个列的值。

以下是使用PDO的示例:

$stmt = $DB->prepare("SELECT name FROM items WHERE id=?");
$stmt->execute([$_REQUEST['id']);
$name = $stmt->fetchColumn();

没那么多,对吗?无需初始化。无需绑定。

确实,为了防止SQL注入,转换为int是安全的。但我更喜欢一直使用查询参数,所以我的代码是一致的。我不需要考虑我正在搜索的参数是否实际上是一个整数。我不必考虑是否可以使用(int)进行SQL注入是安全的。

只需使用参数。

它对任何数据类型都是安全的。

编写代码很容易。

人们很容易阅读您的代码。


1
投票

是的,将输入转换为整数足以防止SQL注入攻击。

您应该仍然像您一样验证结果的范围。


1
投票

在这种情况下,这不能被利用,因为你将请求id的值转换为int,你总是会得到一个整数,即使somephrase被发送,将它转换为int将导致0所以这不能被利用。

但是,使用预处理语句更好,(不安全 - 两种方法都是安全的),原因是习惯了它,因此您不需要通过运行准备好的语句来强制转换或清理任何给定的变量数据库驱动程序正在清理这些值,一切都是安全的。同样,这种将变量转换为int的方法无法被利用。

以下是如何在您的案例中验证输入的示例:

<?php


$id = (int) $_GET['id'];

if($id === 0 || !in_array($id,range(1,255)) 
{
   if($id === 0 && (string) $_GET['id'] !== '0') {
      // sql injection attempt ! ( or not ? )
   } else {
      // maybe an error  
   }
} else {
  $result = $DB->query(...);
  echo $result;
}

1
投票

您的用例似乎更进一步形成一个简单的“确保这是一个整数”测试。我建议你使用PHP工具来完成工作,filter_input()

filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT, [ 
     "options" => [
        "min_range" => 1,
        "max_range" => 255
    ]    
]);

这将为你节省一个if(和一个isset检查)但是如果它失败你不知道它是否失败,因为它没有设置或它不在范围内。

就SQL注入而言,这应该足够了。


1
投票

是的,转换为整数将清理你的用户输入,但如果考虑PHP的type juggling(所有字符串都转换为0,但是如果输入是十进制数字,如果输入为(int) ((0.1+0.7) * 10);,则可能会出现意外结果)会导致错误产量7)。

The Hitchhiker's Guide to SQL Injection prevention建议对数字进行消毒

  • 用准备好的陈述

要么

  • 将它们格式化为仅包含数字,小数分隔符和符号

0
投票

你可以这样做,但PHP已经提供了输入参数验证的工具。看看http://php.net/manual/en/filter.filters.php

这是一个例子:

$options = [
    'options' => [
        'default'   => null,
        'min_range' => 1,
        'max_range' => 255,
    ]
];

if (isset($_REQUEST['id'])) {
    $id = filter_var($_REQUEST['id'], FILTER_VALIDATE_INT, $options);
    if ($id) {
        // TODO:
    }
}

即使进行了所有这些过滤,您仍必须使用SQL参数绑定来访问用于访问数据库的任何库。


-1
投票

技术上 - 是的。

但是,这并不意味着您应该有任何想法在生产代码中的任何地方使用它。

而不是您在此处发布的非最佳代码,请尝试改进它。例如,即使是原始数据库包装器也可以使您的代码成为可能

$name = $DB->run("SELECT name FROM items WHERE id=?", [$_REQUEST['id']])->fetchColumn();

这将是行业标准的安全,快速和肮脏,足以满足您的口味,也足够灵活,可用于任何其他查询或返回格式。

© www.soinside.com 2019 - 2024. All rights reserved.