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值,我不在乎.我只想避免沿着小鲍比表的线条滑行.
TL; DR答案是肯定的.当你施放时(int),除了整数之外你什么都得不到.
问题是你可能有一个用例会产生不良行为.我们来看看你的代码
$id = (int)$_REQUEST['id'];
Run Code Online (Sandbox Code Playgroud)
现在,如果我们称之为
page.php?id=lolsqlinjection
Run Code Online (Sandbox Code Playgroud)
随后的值$id是0(所有字符串转换为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这将是有效的输入.
在这种情况下,这不能被利用,因为您将请求 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)