while 循环中生成的链接容易受到 SQL 注入
Links generated in while loop vulnerable to SQL injections
我有一个数据库,用于存储用户和设备的数据。每个用户都有一个设备列表。当用户登录他的帐户时,下面的 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>";
}
该代码还会生成 ON
和 OFF
link,以便用户可以操纵他的设备。例如,当用户单击 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
。
我的问题是如何为设备列表生成 ON
和 OFF
link 并将数据安全地传递给 on.php
和 off.php
文件。
编辑:
我的主要问题是如何为每个用户的设备(每个用户都有不同数量的设备)生成 ON 和 OFF link。当用户单击 ON link 例如 device23(或任何其他设备,最初我不知道设备名称,我从第一个数据库查询中获取设备名称)我必须传递设备名称到 on.php 文件,以便它可以执行更新设备状态的 SQL 查询。
没有什么可以阻止用户在他们的浏览器中输入这样的 url 并执行 link 所做的事情,您正在创建。这是完全有效的(事实上,浏览器通过点击那个 link)
除此之外,是的,您的脚本可用于 sql 注入。您可能需要考虑使用准备好的语句来访问您的数据库 (https://www.w3schools.com/PHP/php_mysql_prepared_statements.asp) 并另外实施某种身份验证机制(如 user/password 身份验证、系统一次性密码等)
更新:
linked(重复)问题的答案似乎很合理,可以防止 sql 在 php 中注入。
on/off-request 的处理程序必须做两件事:
- 检查当前请求是否被授权(使用$_SESSION) - 用户已经登录了吗? 是 - 成功。 否 - 失败。
- 更新记录(table 设备)仅与当前授权的user_id链接。
我建议你开始使用 prepared statements for sql-statements. It will protect you from sql-inject 攻击。
当您在 on.php
中做出 UPDATE
声明时,我会仔细检查该设备是否属于该用户:
$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 函数后检查错误是一种很好的做法。他们 return false 如果有错误,然后由您来检查错误,记录它以便稍后进行故障排除,并终止 PHP 请求带有友好的错误消息。
最后一个问题是您的代码正在更新 GET 请求中的数据。通常建议避免这种情况,因为为您的站点编制索引的搜索引擎将遵循页面上的 GET links。如果搜索引擎索引器可以查看您的 link 页面,它将跟随每个页面,因此所有设备都将打开。
在这种情况下,由于打开设备仅限于登录用户的设备,并且搜索引擎索引器不太可能在会话中记录有效用户,因此它可能不会是风险。但是你应该养成只在你想更新数据的时候使用POST的习惯。
但是您不能对 POST 请求进行简单的 href
link。因此,您必须制作一个锚标记并使用 Javascript 发出 AJAX POST 请求,如上面 RamRaider 的评论中所述。
我有一个数据库,用于存储用户和设备的数据。每个用户都有一个设备列表。当用户登录他的帐户时,下面的 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>";
}
该代码还会生成 ON
和 OFF
link,以便用户可以操纵他的设备。例如,当用户单击 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
。
我的问题是如何为设备列表生成 ON
和 OFF
link 并将数据安全地传递给 on.php
和 off.php
文件。
编辑:
我的主要问题是如何为每个用户的设备(每个用户都有不同数量的设备)生成 ON 和 OFF link。当用户单击 ON link 例如 device23(或任何其他设备,最初我不知道设备名称,我从第一个数据库查询中获取设备名称)我必须传递设备名称到 on.php 文件,以便它可以执行更新设备状态的 SQL 查询。
没有什么可以阻止用户在他们的浏览器中输入这样的 url 并执行 link 所做的事情,您正在创建。这是完全有效的(事实上,浏览器通过点击那个 link)
除此之外,是的,您的脚本可用于 sql 注入。您可能需要考虑使用准备好的语句来访问您的数据库 (https://www.w3schools.com/PHP/php_mysql_prepared_statements.asp) 并另外实施某种身份验证机制(如 user/password 身份验证、系统一次性密码等)
更新: linked(重复)问题的答案似乎很合理,可以防止 sql 在 php 中注入。
on/off-request 的处理程序必须做两件事:
- 检查当前请求是否被授权(使用$_SESSION) - 用户已经登录了吗? 是 - 成功。 否 - 失败。
- 更新记录(table 设备)仅与当前授权的user_id链接。
我建议你开始使用 prepared statements for sql-statements. It will protect you from sql-inject 攻击。
当您在 on.php
中做出 UPDATE
声明时,我会仔细检查该设备是否属于该用户:
$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 函数后检查错误是一种很好的做法。他们 return false 如果有错误,然后由您来检查错误,记录它以便稍后进行故障排除,并终止 PHP 请求带有友好的错误消息。
最后一个问题是您的代码正在更新 GET 请求中的数据。通常建议避免这种情况,因为为您的站点编制索引的搜索引擎将遵循页面上的 GET links。如果搜索引擎索引器可以查看您的 link 页面,它将跟随每个页面,因此所有设备都将打开。
在这种情况下,由于打开设备仅限于登录用户的设备,并且搜索引擎索引器不太可能在会话中记录有效用户,因此它可能不会是风险。但是你应该养成只在你想更新数据的时候使用POST的习惯。
但是您不能对 POST 请求进行简单的 href
link。因此,您必须制作一个锚标记并使用 Javascript 发出 AJAX POST 请求,如上面 RamRaider 的评论中所述。