I have a PHP app that uses a $_GET
parameter to select JS/CSS files on the filesystem.
If I deny all requests in which the input string contains ./
, \
or a byte outside the visible 7-bit ASCII range, is this sufficient to prevent parent directory traversals when the path is passed to PHP's underlying (C-based) file functions?
I'm aware of null-byte vulnerabilities, but are there any other alternative/malformed character encodings tricks that might squeak by these checks?
Here's the basic idea (not production code):
$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);
Update: My question is really about how the C filesystem functions interpret arbitrary ASCII sequences (e.g. if there are undocumented escape sequences), but I realize this is likely system-dependent and perhaps unanswerable in practice.
My active validation additionally requires that realpath($fullPath)
start with realpath($_SERVER['DOCUMENT_ROOT'])
, ensuring that the file is within the DOC_ROOT, but a goal of this posting was to ditch realpath()
(it's proven unreliable in various environments) while still allowing unusual, but valid URIs like /~user/[my files]/file.plugin.js
.