我使用该open
命令在我的文件系统上打开 HTTP 地址或文件。../../etc/passwd
是否可以将此命令限制到特定目录或无法传递路径?
我知道在 PHP 中,您可以使用open_basedir
指令将用户囚禁到目录中。有没有类似的东西来保护open
命令?
您可以这样做,但您必须检查路径以确保它没有指向您所需的沙箱之外。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"