开关功能SQL注入安全吗?

主权

我正在尝试使用可变的列名访问数据库中的条目。

我有此表,其中包含可以属于三类(汽车,自行车,卡车)之一的车辆:

车辆 自行车 卡车
汽车1 X
2号车 X
自行车1 X
卡车1 X

使用OOP和PDO,我正在尝试访问属于某个类别的车辆。像这样:

用户输入:

 URL: ?category=cars

以下所有内容都在一个名为“车辆”的类中。

车辆制造商:

public function __construct() {

  $this->category = $_GET["category"] ?? "cars";

  switch ($this->category) {
  default: //Avoiding db-error messages by setting default category to "car"
  case "cars":
    $this->category = "car";
    break;
  case "bikes":
    $this->category = "bike";
    break;
  case "trucks":
    $this->category = "truck";
    break;
 }

然后,我从数据库访问与类别相对应的条目:

public function getVehiclesFromCategory() {

    $sql = "SELECT * FROM vehicles WHERE $this->category IS NOT NULL";
    $stmt = $this->connect()->query($sql);

    while ($row = $stmt->fetch()) {
        $row["vehicle"]."<br>";
    }
}

然后,我创建对象以从所选类别中获取输出:

$Vehicles = new Vehicle();
$Vehicles->getVehiclesFromCategory();

我基本上是将用户输入与预定义值相关联。这足以避免SQL注入吗?

我确实意识到我使用的是错误的数据库设计,因为用户不应获得有关数据库列名称的任何提示。我还知道,我应该避免与数据库有关的错误消息,这些消息可能对黑客有用(这就是为什么我使用默认开关的原因)-但目前我需要使用当前的数据库模型进行快速修复。

史蒂文

好像这个问题(“安全吗?”)已经回答了。但是,如何以及为什么似乎有点悬而未决,所以这里有一些进一步的信息...

为什么安全

在这种情况下,使您免于SQL注入件事就是您defaultswitch语句中设置了大小写没有这个词,您将很容易接受SQL注入。让我们玩一下:

有效的输入示例

  1. 用户输入 bikes
  2. 您的代码将category属性设置bikes
  3. switch运行并被bikes发现,因此返回bikecategory

输入示例无效

  1. 用户输入 hairStraightener
  2. 您的代码将category属性设置hairStraightener
  3. 您的switch跑步hairStraightener未找到,因此返回carcategory就是这种default情况

无效情况,无默认

  1. 用户输入 hairStraightener
  2. 您的代码将category属性设置hairStraightener
  3. 您的switch跑步,hairStraightener但未找到,因此category不会更新,并保持为hairStraightener

现在,假设用户输入了以下内容:

1; DROP TABLE vehicles; --

// OR...

1; UPDATE TABLE vehicles SET price = 1; --

现在您丢失了数据负载,或者商店中的所有商品都花费了1英镑(讨价还价!)

改善事情

您处于正确的位置:如果您需要直接在SQL查询中输入变量,则需要将可接受的项目列入白名单并仅使用这些项目。有不同的方法来做...

  1. 就像你有一个 switch/case
  2. 带有match(PHP 8+)
  3. array和查找
  4. 通过对照数据库模式检查变量

转变

我所遇到的最大问题是,如果有人来查看您的代码,他们很可能会发现您已经在之前有效地设置了默认值switch,从而消除了这种default情况。这将使您易于进行SQL注入。

因此,您应该相应地更新代码:

  • 永远不要将用户输入设置为category属性
  • 设置categoryon声明的默认属性

例如

public $category = "car";

public function __construct()
{
  switch ($_GET["category"] ?? null) {
    case "cars":
        $this->category = "car";
        break;
    case "bikes":
        $this->category = "bike";
        break;
    case "trucks":
        $this->category = "truck";
        break;
    }
}

比赛

正如@Dharman所评论的,如果您的服务器运行的是PHP 8+,则可以使用match在这种情况下,您可以将其视为类型敏感的switch语句:

注意:match如果您不提供包装default盒,将抛出错误或者更确切地说,如果提供了一个无法匹配的值!

function __construct()
{
    $this->category = match($_GET["category"] ?? "cars") {
        "cars"   => "car",
        "bikes"  => "bike",
        "trucks" => "truck",
        default  => "car"
    };
}

数组查找

private $allowedFields = [
    "cars"  => "car",
    "bikes" => "bike",
];

public function __construct()
{
  $this->category = $this->allowedFields[$_GET["category"] ?? "cars"];
}

数据库架构

最后,您可以通过检查数据库模式(类似于)并检查输入是否与列名之一匹配来自动生成安全字段DESCRIBE vehicles在您的情况下,虽然这可能不是最好的主意,因为您仍然可以让某人输入不想要真实字段也许这不会是灾难性的,但这绝对不是故意的!

长期修复

正如其他人所说,这是一个有缺陷的数据库设计。大概看起来像:

vehicles
    id
    make
    model
    price
    ...
    bike
    car
    van
    truck
    ...

什么时候看起来应该更像:

vehicle     <    vehicleType      >    type
    id              id                    id
    make            vehicle_id            name
    model           type_id
    price
    ...

然后,您将SQL更新为如下所示:

SELECT
    vehicle.id, vehicle.make, vehicle.model, vehicle.price,
    type.name
FROM vehicle
JOIN vehicleType on vehicle.id          = vehicleType.vehicle_id
JOIN type        on vehcileType.type_id = type.id
WHERE type.name = ?

现在,您可以使用准备好的语句来完全安全了

NB

创建两个表并将现有的表更新到其中似乎是一个耗时的过程。但实际上并不会花那么长时间。过程:

  1. 使用适当的数据类型,属性等创建表。
  2. DESCRIBEvehicles表和提取物中的不同类型的(carbike等)
  3. 将类型插入表格 type
    • 例如,可以使用几行PH​​P来自动完成所有操作
  4. 编写一个简短的脚本来循环遍历车辆表的每一行,并根据列数将insert记录记录到vechicleType表中not null
  5. 检查您的数据(根据需要备份)
  6. 从中删除不再需要的列 vehicles

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

SQL注入-此查询安全吗?

来自分类Dev

这是SQL查询,注入安全吗

来自分类Dev

我安全吗?[试图防止SQL注入]

来自分类Dev

在rails中find_by_id sql注入安全吗?

来自分类Dev

Windows允许的文件名对注入安全吗?(SQL,JavaScript等)

来自分类Dev

PHP-PDO引用对SQL注入安全吗?

来自分类Dev

Python SQL 注入安全

来自分类Dev

SQL注入功能--

来自分类Dev

'-+'的SQL注入功能

来自分类Dev

变量可以包含功能开关吗?

来自分类Dev

SQL注入的安全性

来自分类Dev

AJAX的带有准备好的语句的发布对SQL注入安全吗?

来自分类Dev

JavaScript形式的密码注入安全吗?

来自分类Dev

JavaScript形式的密码注入安全吗?

来自分类Dev

TFDTable.AppendRecord注入安全吗

来自分类Dev

温泉开关不记得它的状态(并且未检查开关的呼叫功能)吗?

来自分类Dev

PDO SQL注入安全性

来自分类Dev

静态无功能线程安全吗?

来自分类Dev

反伪造令牌功能安全吗?

来自分类Dev

反伪造令牌功能安全吗?

来自分类Dev

django sql线程安全吗?

来自分类Dev

可以在开关中开关吗?

来自分类Dev

PDO和MySQL的这种实现对MySQL注入安全吗?

来自分类Dev

PDO和MySQL的这种实现对MySQL注入安全吗?

来自分类Dev

C#Linq to SQL包含用于SQL注入的安全

来自分类Dev

C#Linq to SQL包含用于SQL注入的安全

来自分类Dev

C#Linq to SQL包含用于SQL注入的安全

来自分类Dev

CallableStatement真的不受SQL注入的影响吗?

来自分类Dev

CallableStatement真的不受SQL注入的影响吗?