【问题标题】:Is it necessary to protect destroy method in Laravel from an authenticated user that did not create a post是否有必要保护 Laravel 中的 destroy 方法免受未创建帖子的经过身份验证的用户的影响
【发布时间】:2021-09-22 15:56:51
【问题描述】:

我的PostController 中有以下中间件。

public function __construct()
    {
        $this->middleware('auth')->except(['index', 'show']);
    }

我了解任何经过身份验证的用户仍然可以通过访问 localhost/posts/{post}/edit 来编辑帖子,因此我已通过以下代码对其进行保护。

 public function edit(Post $post)
    {
        if(auth()->user()->id === $post->user_id){
            $categories = Category::all();
            return view('edit-post', compact(['post', 'categories']));
        } else{
            abort(403, 'Unauthorized.');
        }

    }

现在,我想知道是否有必要保护 destroy 方法?在这种情况下,经过身份验证的用户是否可以删除他们没有创建的帖子?如果他们可以,我能知道他们怎么做吗?

我的销毁方法

   public function destroy(Post $post)
    {
        Storage::disk('public')->delete($post->imagePath);
        $post->delete();
        return redirect(route('posts.index'))->with('flash', 'Post Deleted Successfully');
    }

【问题讨论】:

    标签: laravel middleware


    【解决方案1】:

    保护所有需要身份验证的方法的一种简单方法是使用关系。

    您通过使用模型注入从 DB 预加载 $post 在 URL 中发送一个帖子 ID。避免这种情况并自己使用帖子的ID

    public function destroy($postId)
        {
            $post = auth()->user()->posts()->findOrFail($postId);
            Storage::disk('public')->delete($post->imagePath);
            $post->delete();
            return redirect(route('posts.index'))->with('flash', 'Post Deleted Successfully');
        }
    

    如果帖子 ID 不是用户拥有的帖子之一,该路由将返回 404。

    编辑也一样

    public function edit($postId)
    {
        $post = auth()->user()->posts()->findOrFail($postId);
        $categories = Category::all();
        return view('edit-post', compact(['post', 'categories']));
    }
    

    至于响应代码 404 而不是 403 的更改,这是故意的,因为用户已通过身份验证,并且您不希望任何用户知道是否存在另一个具有非他的随机 ID 的帖子,因此 404。就像他把一个不存在的帖子 ID 删除或编辑一样。

    【讨论】:

    • 我同意 404 而不是 403,谢谢。关于建议的方法,有2个问题:1.路由模型绑定方式有问题为什么要避免?因为无论哪种方式我都可以,如果我以与编辑方法相同的方式保护销毁方法,它仍然可以工作。 2. 一个经过身份验证的用户如何删除他们没有创建的帖子而不检查他们是否是在destroy方法中创建帖子的人。我很好奇,我想实际执行一下,看看是否有必要保护它免受经过身份验证的用户的影响?
    • @AlphyGacheru 1- 并非在每种情况下都必须使用每个功能。在这里,您需要删除会话中与用户相关的帖子,而模型绑定只是严格按 id 加载帖子。(如果它在管理控制器中,模型绑定将非常适合使用) 2-使用我提出的方法。它不会做额外的查询或任何事情,因为您使用了两个索引(user_id & posts.id),所以查询速度更快
    • 我明白你的意思,虽然我不确定你是否回答了我的最后一个问题,或者我是那个不明白的人,但我同意了。我的意思是,如果我想编辑不受保护的帖子,我会访问localhost/posts/{post}/edit。假设我们没有保护 destroy 方法,我需要访问什么 url 来删除帖子?
    • 嗯?你的问题对我来说不清楚,但如果我做对了,假设一个路由是 post 方法,你不能从浏览器的栏访问它(get 方法)将返回 405 Method Not Allowed。
    • 我同意最后一条评论中的@N69S,简短的回答是DON'T TRUST THE CLIENT
    【解决方案2】:

    首先,您应该了解Laravel policy,这将使您的代码更加清晰。

    对于销毁方法,

    我给你一个例子,你可以试试看

    post_table

    id user_id title
    1 40 Post1
    2 50 Post2

    如果用户id: 40尝试删除帖子女巫id是id: 1没有问题, 但是假设用户知道网络应用程序并且只是更改 URL localhost/posts/2/delete 中的 id,他/她将删除任何没有政策的帖子。

    【讨论】:

    • 试过但没有删除。它抛出了一个错误:404 | NOT FOUND
    • 你确定数据库中有相同id的帖子吗?
    • 是的,>>> Post::find(23) [!] Aliasing 'Post' to 'App\Models\Post' for this Tinker session. => App\Models\Post {#4412 id: 23, user_id: 1, category_id: 1, title: "mmmmmmmmmmmmmmm", imagePath: "postImages/m8pjvkyVK1bvKLSmSmyV7MiCgQNVBysOQOw2gref.jpg", body: "nb", slug: "mmmmmmmmmmmmmmm", created_at: "2021-09-22 15:35:49", updated_at: "2021-09-22 15:35:49", } >>>
    • 可能问题出在路由列表上,反正我一步一步解释,假设路由看起来像Route::delete('/posts/{post}/delete', [App\Http\Controllers\PostController::class, 'destroy']);,攻击者注册为用户,他/她知道没有policysif condition,他会在 URL 或表单中搜索以获取 id(主键),很容易,攻击者将通过编辑 HTML url 表单或使用邮递员发出删除请求;我希望这很清楚,让我们按逻辑移动到 controller@destroy 函数查找帖子,如果找到它,如果不返回 404 就删除它。
    • 我明白了,我仍在试图弄清楚为什么我的没有删除以查看它的实际效果。这就是我在运行 route:list | DELETE | posts/{post} 时所拥有的,如果重要的话,我也在使用 my RouteKeyName as 'slug'
    猜你喜欢
    • 1970-01-01
    • 2020-05-22
    • 1970-01-01
    • 2021-02-05
    • 2016-01-17
    • 1970-01-01
    • 2010-10-01
    • 2011-07-09
    相关资源
    最近更新 更多