1

我们正在使用refile来允许用户将图像上传到我们的 S3 后端。此外,我们允许用户选择输入 Internet 上任何图像的 URL(通过remote_image_url属性)。

只要输入的 URL 指向一个实际的文件,它就可以正常工作。但是,如果 URL 有错误,或者给出了一些无意义的输入,Refile则会抛出以下异常:

Errno::ENOENT (No such file or directory @ rb_sysopen - thiswillnotwork):
  app/controllers/my/deals_controller.rb:17:in `create'
  appsignal (0.11.2) lib/appsignal/rack/listener.rb:13:in `call'

是否有一个选项可以忽略输入的 URL 无效的情况(类似于validate_downloadCarrierWave 中的选项如何工作),并且理想情况下,使用我们的后备图像代替?

我们尝试使用raise_errors设置为 的选项安装附件false,但结果相同。

我们的项目使用Rails 4.2.0Refile 0.5.3.

编辑:

我已确认此异常是较低级别的SystemCallError,来自Kernel.open,并且此异常类型没有被 Refile 抢救:

rescue OpenURI::HTTPError, RuntimeError => error
  raise if error.is_a?(RuntimeError) and error.message !~ /redirection loop/
  @errors = [:download_failed]
  raise if @raise_errors
end

我正在处理重新提交以解决此问题的拉取请求。

编辑2:

在处理这个问题时,我们发现了一个重大的安全问题Refile使潜在的攻击者能够使用远程代码执行。

Refile gem 具有将提供 URL 并上传远程文件的功能。这可以通过remote_image_url在表单中​​添加一个字段来完成,其中image是附件的名称。此功能使用 open-uri 发出此 HTTP 请求,而无需验证传递的 URI。攻击者可以制作一个在主机上执行任意 shell 命令的 URI。

如果您使用Refile版本0.5.0- 0.5.3,请升级到最新版本。升级也将解决上述问题。

4

1 回答 1

0

在与 的维护者交谈后Refile,这将在下一次迭代中修复。现在,我们已经创建了以下简单的 Ruby 类作为解决方法。

# app/services/remote_url.rb
class RemoteUrl
  def initialize(url)
    @url = url
  end

  def valid?
    URI.parse(@url).kind_of?(URI::HTTP)
  rescue URI::InvalidURIError
    false
  end
end

我在我的控制器中使用它,如下所示:

# app/controllers/model_controller.rb
def model_params
  sanitize_remote_url!
  params.require(:model).permit(:description, ..., :image, :remote_image_url)
end

def sanitize_remote_url!
  params[:model].delete(:remote_image_url) unless RemoteUrl.new(params[:model][:remote_image_url]).valid?
end

这是一种相当原始的方法,但考虑到它将在下一个 Gem 版本中进行修补,我认为这已经足够了。

免责声明:

虽然这抵消了原始问题的编辑 2中提到的一些漏洞,但攻击者仍然可以远程执行代码,如果他们可以http:在文件系统上创建一个名为的文件夹,如字符串之类http:/../etc/passwd的将通过 URL 验证,但仍然通过Kernel.open.

Gem 现已修补 ( 0.5.4),升级是正确的解决方案。

于 2015-04-07T06:58:15.403 回答