如何限制打开(...)到目录?

时间:2013-06-02 14:10:27

标签: ruby file security

我使用open命令在我的文件系统上打开HTTP地址或文件。是否可以将此命令限制为特定目录o是否无法传递类似../../etc/passwd的路径?

我知道在PHP中你可以使用open_basedir指令将用户监禁到一个目录。是否有类似的安全open命令?

1 个答案:

答案 0 :(得分:1)

您可以这样做,但您必须检查路径以确保它不会指向您想要的沙箱之外。 open不会为你做这件事。

看看File.realpath。它解析路径中的..个组件,为您提供所请求的实际路径。该路径必须存在或realpath将引发异常,这是您无法提供该文件的第一个提示。您需要救出Errno::ENOENT

File.realpath('/usr/bin') # => "/usr/bin"
File.realpath('/tmp') # => "/private/tmp"

File.realpath('/foobar') 
Errno::ENOENT: No such file or directory - /foobar

然后,您可以使用简单的正则表达式进行检查,以确保生成的路径锚定在您允许的区域中。这是代码的一个例子。

SHARED_PATH_REGEXP = /\A#{ Regexp.escape(File.realpath('/path/to/shared/content')) }/i

def is_shared_path?(requested_path)
  real_requested_path = File.realpath(requested_path)
  !!real_requested_path[SHARED_PATH_REGEXP]
rescue Errno::ENOENT
  false
end

path_received('/etc/passwd') # => false
path_received(SHARED_PATH_REGEXP + '/foo.html') # => true

Regexp.escape对预处理文件字符串非常有用,因此正则表达式引擎会进行文字检查:

Regexp.escape('/usr/bin')  # => "/usr/bin"
Regexp.escape('../../public')  # => "\\.\\./\\.\\./public"