Laravel 嵌套资源安全

Laravel nested resource security

在我目前正在进行的项目中,我有这样的嵌套资源

route()->resources('user', 'UserController');
route()->resources('user.place', 'PostController');
route()->resources('user.place.picture', 'PictureController');

一切正常,我每次都传递用户 ID 等...

诀窍是当你来到一个地方时,如果这是你的,我会显示按钮来编辑和进行一些操作。所以我检查 $place.user_id == $user.id 是否显示按钮。

玩了一会儿之后,因为要访问例如我的一个地方,我有以下 URL : /user/1/place/2 for the Place.show.

我是所有者,所以按钮显示并且我可以修改,但是如果另一个用户(例如 user_id 2)使用相同的 URL 查看我的地方,他不能修改任何东西但可以看到的地方。

我发现如果此用户使用相同的 URL 但将 user_id 更改为我的,那么他可以完全访问该位置并进行修改。

所以为了防止这种情况,我添加了另一个条件:Auth::user()->id == $user->id

我想知道是否有解决方案来防止这种行为,因为如果我必须保护嵌套资源的每个方法,它的实现就会变得冗长和难看。还有当我进入下一个级别时user.place.picture。我想我每次下来都需要增加另一层安全性。 $picture->place_id == $place->id 等等。

因此,当我打印 link 以便用户可以使用正确的用户、地点、图片 ID 单击它时,不会阻止或检查一个 ID 是否已被修改。如果修改了最后一个元素,则没有问题,因为它会检索另一个元素。但是,如果我们修改父级的 ID,则可能会很危险,尤其是当我在此过程中授予一些访问权限时。

希望有一个我错过的简单解决方案!

首先,我认为您根本没有必要进行这项检查;

$place.user_id == $user.id

因为正如您所发现的,从 URL 派生的 $user 很容易被操纵,因此该守卫没有任何价值。您已经 添加了 检查以确保当前登录的 UserPlace 的所有者,但这应该是您唯一的检查,但您没有两者都需要。

如果我没理解错的话,这听起来像是使用 Policies in Laravel 的完美用例。该文档非常全面,但我会尝试针对您的特定用例进行总结:

  • 生成 Policy,例如PlacePolicy
  • 对于您的用例,在此策略中,您将创建一个接受参数的 update() 方法,User(登录用户)和 Place(位置他们正在尝试访问)
  • PlacePolicy 上的 update() 方法现在可以通过任何方式确定 User 是否可以更新 Place

所以,它可能看起来像这样;

<?php

namespace App\Policies;

use App\Place;
use App\User;

class PlacePolicy
{
    /**
     * Determine if the given place can be updated by the User.
     *
     * @param  \App\User  $user
     * @param  \App\Place  $place
     * @return bool
     */
    public function update(User $user, Place $place)
    {
        return $place->user_id == $user->id;
    }
}

这是一个非常简单的检查 - 但您基本上可以在这里做任何事情来确定给定的用户是否可以对另一个模型执行操作。

注意:您需要在服务提供商中注册此策略,请参阅上面链接的文档了解如何执行此操作

有了这个 Policy,您就可以利用 Laravel 提供的一系列有用的工具。例如,您可以利用 Blades can 指令来执行如下操作:

@can('update', $place)
    < SHOW THE EDIT BUTTON >
@endcan

您还可以通过 Middleware 应用 Policy 类 以首先阻止页面被访问:

Route::get('/user/{user}/place/{place}' .....)->middleware('can:update,place');

希望这足以让您上路! :)