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

时间:2018-02-22 17:31:57

标签: php mysqli casting sql-injection

引自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];

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

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

7 个答案:

答案 0 :(得分: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为&#34; lolsqlinjection&#34;的项目。没有这样的记录。因此,我们避免了0将成为有效输入的任何潜在边缘情况。

答案 1 :(得分: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;
}

答案 2 :(得分:1)

您的用例似乎更进一步形成一个简单的&#34;确保这是一个整数&#34;测试。我建议您使用PHP工具进行工作filter_input()

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

这样可以为你节省一笔if(以及一张isset检查),但如果失败了,你就不知道它是否因为没有设置或者不在范围内而失败了

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

答案 3 :(得分:1)

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

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

答案 4 :(得分:1)

是的,如果您考虑使用PHP type juggling(所有字符串都转换为0,那么转换为整数会清理您的用户输入,但会出现问题并导致错误 ,但如果输入是十进制数,您也会有意外结果,例如(int) ((0.1+0.7) * 10);会产生7)。

The Hitchhiker's Guide to SQL Injection prevention建议按

清理数字
  • 使用预备陈述

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

答案 5 :(得分:0)

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

以下是一个例子:

{{1}}

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

答案 6 :(得分:-1)

技术上 - 是的。

但是,这并不意味着你应该知道在生产代码中的任何地方使用它。

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

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

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