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

Dok*_*r J 4 php mysqli casting sql-injection

引用这个SO答案:

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

这是我独立提出的一种快速和脏查询的清理方法(从数字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];
Run Code Online (Sandbox Code Playgroud)

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

注意:ID /名称不是"敏感",所以如果某些输入无意中转换为"1"或其他有效的ID值,我不在乎.我只想避免沿着小鲍比表的线条滑行.

Mac*_*ity 5

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

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

$id = (int)$_REQUEST['id'];
Run Code Online (Sandbox Code Playgroud)

现在,如果我们称之为

page.php?id=lolsqlinjection
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • “bind_param()”中的“i”是否也强制它将字符串转换为“int”?如果你使用`s`,MySQL在进行比较时会将字符串转换为int。这些都会将其视为“0”,就像 PHP 中的“(int)”一样。 (2认同)

sai*_*aif 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;
}
Run Code Online (Sandbox Code Playgroud)