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

Ste*_*lay 4 php filesystems validation character-encoding

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

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

我知道空字节漏洞,但有没有其他替代/格式错误的字符编码技巧可能会被这些检查吱吱作响?

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

$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);
Run Code Online (Sandbox Code Playgroud)

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

我的主动验证还需要realpath($fullPath)realpath($_SERVER['DOCUMENT_ROOT'])确保文件在DOC_ROOT内开始,但这个帖子的目标是放弃realpath()(它在各种环境中被证明是不可靠的),同时仍然允许不寻常但有效的URI /~user/[my files]/file.plugin.js.

SLa*_*aks 5

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

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

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