Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Secure method to download files in Ruby

Tags:

A common way to download files in Ruby is using the open-uri library and simply calling open(url). However, it has been pointed out that this passes input along to Kernel#open, which is not safe to call with untrusted input (starting with a pipe spawns a subprocess, etc).

What is the best practice way to securely download a file in Ruby when the URL is constructed from potentially untrusted user input?

like image 454
jrdioko Avatar asked Jan 12 '18 17:01

jrdioko


1 Answers

Firstly, consider why are you allowing this in the first place? Giving users the power to open arbitrary URLs on the server is an unusual (and "dangerous") thing to be doing in the first place!

For instance, even if you were to protect against process spawns, the user could still open arbitrary code from the internet - e.g. a virus.

It is most likely that any system allowing this will already trust its users. For example, perhaps the only user is yourself!!

...With that said, here is the source code for Kernel#open when you have also used require '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

So for the use case of only opening a URL, you can see that the implementation is to call: URI.parse(url).open. Therefore, your "secure" code could be implemented as:

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

...But remember, as I said above, you really need to think twice before downloading arbitrary URLs! You should probably only being doing this if you already trust the user input; in which case my above code is likely unnecessary!

like image 95
Tom Lord Avatar answered Sep 19 '22 13:09

Tom Lord