重新归档 Gem:当remote_image_url无效或不存在时忽略异常



我们使用refile允许用户将图像上传到我们的S3后端。此外,我们允许用户选择输入互联网上任何图像的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无效的情况(类似于CarrierWave中的validate_download选项),理想情况下,使用我们的回退图像?

我们已经尝试在raise_errors选项设置为false的情况下安装附件,但结果相同。

我们的项目使用Rails 4.2.0Refile 0.5.3

编辑:

我已经确认,此异常是来自Kernel.open的较低级别SystemCallError,并且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是附件的名称。此功能使用开放uri发出此HTTP请求,而不验证传递的uri。攻击者可以在主机上创建一个执行任意shell命令的URI。

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

在与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版本中进行修补,我认为目前这已经足够好了。

免责声明:

尽管这抵消了原始问题的edit2中提到的一些漏洞,但如果攻击者能够在文件系统上创建名为http:的文件夹,则攻击者仍然能够执行远程代码,因为像http:/../etc/passwd这样的字符串将通过URL验证,但仍能通过Kernel.open读取本地文件。

Gem现在已经打了补丁(0.5.4),升级是正确的解决方案。

最新更新