在Ruby中下载文件的安全方法

时间:2018-01-12 17:55:25

标签: ruby http security

在Ruby中下载文件的常用方法是使用open-uri库并简单地调用open(url)。但是,pointed out将输入传递给Kernel#open,使用不受信任的输入调用是不安全的(从管道生成子进程开始等)。

当从可能不受信任的用户输入构建URL时,在Ruby中安全下载文件的最佳实践方法是什么?

2 个答案:

答案 0 :(得分:2)

首先,考虑一下你为什么首先允许这个?让用户有权在服务器上打开任意网址 ,这是一件不寻常的事情(而且"危险的")首先要做的事情!

例如,即使你要防止进程产生,用户仍然可以从互联网上打开任意代码 - 例如病毒。

任何允许此操作的系统很可能已经信任其用户。例如,也许唯一的用户就是你自己!!

...话虽如此,当您使用Kernel#open 时,hererequire 'open-uri' 的源代码:

alias open_uri_original_open open

def open(name, *rest, &block)
  if name.respond_to?(:open)
    name.open(*rest, &block)
  elsif name.respond_to?(:to_str) &&
        %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} =~ name &&
        (uri = URI.parse(name)).respond_to?(:open)
    uri.open(*rest, &block)
  else
    open_uri_original_open(name, *rest, &block)
  end
end

因此,对于打开URL的用例,您可以看到实现是调用:URI.parse(url).open。因此,您的安全"代码可以实现为:

def open_url(url)
  if url =~ URI.regexp
    URI.parse(url).open
  else
    # Handle this somehow?
  end
end

...但请记住,正如我上面所说,在下载任意网址之前,你真的需要三思而后行!如果已经信任用户输入,您可能应该只这样做;在这种情况下,上面的代码可能是不必要的!

答案 1 :(得分:0)

如本文所建议:https://twin.github.io/improving-open-uri/

内核#打开

Ruby有一个Kernel#open方法,给定的文件路径充当File.open。但是给定以“ |”开头的字符串,它将其解释为shell命令,并返回连接到生成的子进程的IO:

open("| ls") # returns an IO connected to the `ls` shell command

Open-uri通过接受URL的功能扩展了Kernel#open。但是,如果URL来自用户输入,则永远不要将其传递给Kernel#open,因为不同的用户对什么是“ URL”有不同的想法;有人可能会认为| rm -rf ~是一个漂亮的网址。

一个鲜为人知的事实是Kernel#open仅委托给URI::(HTTP|HTTPS|FTP)#open,我们可以简单地使用它:

uri = URI.parse("http://example.com/image.jpg") #=> #<URI::HTTP>
uri.open #=> #<Tempfile:/var/folders/k7/6zx6dx6x7ys3rv3srh0nyfj00000gn/T/20160524-10403-xpdakz>