2

我正在迁移到 ActiveStorage 一个权限敏感的应用程序。我需要确保只有具有权限的人才能访问文件,并且这些权限仅持续指定的时间段。

使用 Paperclip,这就像使用权威人士授权调用定义路由一样简单:

def thumbnail
    authorize @record
    redirect_to @record.thumbnail.expiring_url(300)
end

任何调用/record/thumbnail都将由 devise 进行身份验证,由 pundit 授权,然后使用过期 url 重定向到 S3。这是一个行之有效的过程。

转向 ActiveStorage,我最初的想法是我会使用service_url,但它仅在我使用 S3 时才有效——它在测试中不起作用,如果我在使用磁盘服务进行本地开发时它不起作用。实际的“正确”方法是使用url_for, 或在上面的示例中redirect_to url_for @record.thumbnail

问题是,url_for似乎发出了一个永久 url——它生成的 url 对于任何人都是有效的,无需身份验证或授权。更重要的是,一旦有人有了那个网址,我就不能撤销它,我不能说它只能维持一个星期。一旦有人拥有该网址,他们就可以永远访问该文件。(或者,大概,至少在文件更新之前)。

我不认为这是一个巨大的安全漏洞,但这绝对是使用 Paperclip 可以实现的倒退。我是否遗漏了一个重要的细节,或者这真的是 ActiveStorage 所能做到的吗?

4

1 回答 1

3

文档说:

如果您需要在已签名 blob 引用的隐匿性安全因素之外实施访问保护,则需要实现自己的经过身份验证的重定向控制器。

这不是特别有用。为此,您需要创建自己的控制器来服务 blob:

class BlobsController < ApplicationController
  include ActiveStorage::SetBlob
  before_action :authorize_blob

  def show
    expires_in ActiveStorage::Blob.service.url_expires_in
    redirect_to @blob.service_url(disposition: params[:disposition])
  end

  private

  def authorize_blob
    # Your authorization code goes here
  end
end

然后你需要设置你的路由:

  get '/blobs/:signed_id/*filename' => "blobs#show", as: "service_blob"
  direct :blob do |blob, options|
    route_for(:service_blob, blob.signed_id, blob.filename, options)
  end
  resolve("ActiveStorage::Blob") { |blob, options| route_for(:blob, blob, options) }  

最后,您需要禁用不安全的默认控制器,以便知识渊博的用户无法绕过您的授权。

如果您使用的是 Rails 6.1+,您可以通过config.active_storage.draw_routes在 application.rb 中设置为 false 来做到这一点。但是您需要确保其余的 ActiveStorage 路由是手动绘制的,并且其中有很多。您可以在 Github 上查看它们

否则,您将需要添加扩展控制器以重定向到您的新控制器(或完全关闭它)。您可以将以下内容添加到初始化程序中:

module ActiveStorageRedirect
  def self.included(controller)
    controller.before_action :redirect_to_authenticated
  end

  private

  def redirect_to_authenticated
    redirect_to Rails.application.routes.url_helpers.blob_path(@blob)
  end
end

ActiveStorage::Blobs::RedirectController.include(ActiveStorageRedirect) # For Rails >= 6.1
ActiveStorage::Blobs::ProxyController.include(ActiveStorageRedirect) # For Rails >= 6.1
# ActiveStorage::BlobsController.include(ActiveStorageRedirect) # For Rails < 6.1

于 2021-03-08T16:07:31.443 回答