ASCII“../”是唯一表示PHP中目录遍历的字节序列吗?

时间:2009-10-18 22:31:22

标签: php character-encoding filesystems validation

我有一个PHP应用程序,它使用$_GET参数来选择文件系统上的JS / CSS文件。

如果我拒绝所有输入字符串包含./\或可见7位ASCII范围之外的字节的请求,这足以防止路径传递时父目录遍历到PHP的底层(基于C的)文件函数?

我知道null-byte vulnerabilities,但有没有其他替代/格式错误的角色编码可能会因这些检查而吱吱作响?

这是基本想法(不是生产代码):

$f = $_GET['f']; // e.g. "path/to/file.js"

// goal: select only unhidden CSS/JS files within DOC_ROOT
if (! preg_match('@^[\x20-\x7E]+$@', $f)     // outside visible ASCII
   || false !== strpos($f, "./")             // has ./
   || false !== strpos($f, "\\")             // has \
   || 0 === strpos(basename($f), ".")        // .isHiddenFile
   || ! preg_match('@\\.(css|js)$i@', $f)    // not JS/CSS
   || ! is_file($_SERVER['DOCUMENT_ROOT'] . '/' . $f)) {
    die();
}
$content = file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/' . $f);

更新:我的问题是关于C文件系统函数如何解释任意ASCII序列(例如,如果有未记录的转义序列),但我意识到这可能是系统依赖的,也许在实践中无法解决

我的主动验证另外要求realpath($fullPath)realpath($_SERVER['DOCUMENT_ROOT'])开头,确保该文件在DOC_ROOT内,但此帖子的目标是放弃realpath()(事实证明它不可靠各种环境)同时仍然允许不寻常但有效的URI,如/~user/[my files]/file.plugin.js

3 个答案:

答案 0 :(得分:5)

在过滤输入以确保安全性时,请始终使用白名单,而不是后退列表。

您应该拒绝所有与/^([A-Za-z0-9_-]+\/?)*[A-Za-z0-9_-]+\.(js)|(css)?$/不匹配的路径。

这将只允许正常的分段路径,其中每个分段都有字母,数字或_-

答案 1 :(得分:1)

可能需要稍加重新架构,但即使您通过了../../passwdbasename()也会对其进行隔离。然后,您可以将要提供的所有文件放在一个文件夹中。

鉴于../../././././a/b/c/d.txtbasename($f)将为d.txt;这种方法对我来说似乎更明智,而不是试图超越用户并忘记漏洞。

答案 2 :(得分:1)

您自己提到它,但将输入realpath与已知根进行比较是我能想到的最佳解决方案。 Realpath将解析路径/文件系统的任何隐藏功能,包括符号链接。