在while循环中生成的链接容易受到SQL注入的攻击

时间:2019-03-17 08:55:40

标签: php sql mysqli sql-injection http-get

我有一个数据库,用于存储用户和设备的数据。每个用户都有一个设备列表。当用户登录其帐户时,下面的php代码将生成用户设备的列表:

$query_user="SELECT * FROM devices WHERE users_id = '".$user_id."'";

$result = mysqli_query($db, $query_user);

// generating device list and ON and OFF device links
while($row = $result->fetch_assoc()) 
{
    echo "<br><p>". $row["device"] ."</p><a href=on.php?data=" . $row["device"] . ">ON</a><br><a href=off.php?data=" . $row["device"] . ">OFF</a><br>";
}

该代码还会生成一个ONOFF链接,以便用户可以操纵他的设备。例如,当用户单击ON时,以下URL将传递给浏览器:

https://.../on.php?data=device23

on.php代码中用于处理URL数据的部分:

if(isset($_GET["data"]))
{
    $device_name = $_GET["data"];
}

$query_user="UPDATE devices SET status='ON' WHERE device = '".$device_name."'";

mysqli_query($db, $query_user);

所以我的问题是这种方法容易受到SQL注入的影响,例如有人可以键入:

https://.../on.php?data=device17

在浏览器中,然后打开device17

我的问题是如何为设备列表生成ONOFF链接并将数据安全传递到on.phpoff.php文件。

编辑:

我的主要问题是如何为每个用户设备(每个用户拥有不同数量的设备)生成ON和OFF链接。当用户单击例如device23(或任何其他设备,最初我不知道设备名称,我正在从第一个数据库查询中获取设备名称)的ON链接时,我必须将设备名称传递给on。 php文件,以便它可以执行更新设备状态的SQL查询。

3 个答案:

答案 0 :(得分:1)

UPDATE中进行on.php声明时,我会仔细检查设备是否属于用户:

$query_user = "UPDATE devices SET status='ON' WHERE users_id = ? AND device = ?";

这是解决的一个问题。现在还有其他一些问题。

注意,我避免了通过串联将PHP变量直接放入SQL查询中。这是您确定的SQL注入风险。解决问题的方法是to use query parameters

$stmt = mysqli_prepare($db, $query_user);
if ($stmt === false) {
    error_log(mysqli_error($db));
    die("Sorry, there has been a software error");
}
$ok = mysqli_stmt_bind_param($stmt, "ss", $user_id, $device_name);
if ($ok === false) {
    error_log(mysqli_stmt_error($db));
    die("Sorry, there has been a software error");
}
$ok = mysqli_stmt_execute($stmt);
if ($ok === false) {
    error_log(mysqli_stmt_error($db));
    die("Sorry, there has been a software error");
}

每次调用mysqli函数之一后检查错误是一个好习惯。如果出现错误,它们将返回 false ,然后由您检查并记录下来,以便稍后进行故障排除,并通过友好的错误消息终止PHP请求。

最后一个问题是您的代码正在更新GET请求中的数据。通常建议避免这种情况,因为将您的网站编入索引的搜索引擎将遵循页面上的GET链接。如果搜索引擎索引器可以查看您的链接页面,它将跟随每个链接,因此所有设备都将打开。

在这种情况下,由于打开设备仅限于已登录用户的设备,并且搜索引擎索引器不太可能在会话中记录有效用户,因此可能不会带来风险。但是,只有在要更新数据时,您才应该养成使用POST的习惯。

但是您无法为POST请求建立简单的href链接。因此,您必须制作锚标记,并使用Javascript发出AJAX POST请求,如上面RamRaider的评论中所述。

答案 1 :(得分:0)

没有什么可以阻止用户在其浏览器中键入此类URL并执行您正在创建的链接。这是完全有效的(事实上,浏览器通过单击该链接可以执行任何操作)

此外,是的,您的脚本可以进行sql注入。您可能要考虑使用准备好的语句来访问数据库(https://www.w3schools.com/PHP/php_mysql_prepared_statements.asp),并另外实现某种身份验证机制(例如用户/密码身份验证,系统一次性密码等)

更新: 链接(重复)问题的答案似乎很合理,可以防止php中的sql注入。

答案 2 :(得分:0)

开/关请求的处理程序必须做两件事:

  • 检查当前请求是否已授权(使用 $ _ SESSION )-用户是否已登录? -是成功。 -是失败。
  • 更新记录(表设备)仅与当前授权的 user_id 链接。

我建议您开始将prepared statements用于sql语句。它将保护您免受sql-inject攻击。