aco*_*der 3 php security sanitization
有没有办法安全地消毒路径输入,而不使用realpath()?
目标是防止恶意输入 ../../../../../path/to/file
$handle = fopen($path . '/' . $filename, 'r');
Run Code Online (Sandbox Code Playgroud)
RFC 3986中描述了一种删除点序列算法,用于在相对URI参考解析过程中解释和删除引用路径中的特殊和完整路径段....
您也可以将此算法用于文件系统路径:
// as per RFC 3986
// @see http://tools.ietf.org/html/rfc3986#section-5.2.4
function remove_dot_segments($input) {
// 1. The input buffer is initialized with the now-appended path
// components and the output buffer is initialized to the empty
// string.
$output = '';
// 2. While the input buffer is not empty, loop as follows:
while ($input !== '') {
// A. If the input buffer begins with a prefix of "`../`" or "`./`",
// then remove that prefix from the input buffer; otherwise,
if (
($prefix = substr($input, 0, 3)) == '../' ||
($prefix = substr($input, 0, 2)) == './'
) {
$input = substr($input, strlen($prefix));
} else
// B. if the input buffer begins with a prefix of "`/./`" or "`/.`",
// where "`.`" is a complete path segment, then replace that
// prefix with "`/`" in the input buffer; otherwise,
if (
($prefix = substr($input, 0, 3)) == '/./' ||
($prefix = $input) == '/.'
) {
$input = '/' . substr($input, strlen($prefix));
} else
// C. if the input buffer begins with a prefix of "/../" or "/..",
// where "`..`" is a complete path segment, then replace that
// prefix with "`/`" in the input buffer and remove the last
// segment and its preceding "/" (if any) from the output
// buffer; otherwise,
if (
($prefix = substr($input, 0, 4)) == '/../' ||
($prefix = $input) == '/..'
) {
$input = '/' . substr($input, strlen($prefix));
$output = substr($output, 0, strrpos($output, '/'));
} else
// D. if the input buffer consists only of "." or "..", then remove
// that from the input buffer; otherwise,
if ($input == '.' || $input == '..') {
$input = '';
} else
// E. move the first path segment in the input buffer to the end of
// the output buffer, including the initial "/" character (if
// any) and any subsequent characters up to, but not including,
// the next "/" character or the end of the input buffer.
{
$pos = strpos($input, '/');
if ($pos === 0) $pos = strpos($input, '/', $pos+1);
if ($pos === false) $pos = strlen($input);
$output .= substr($input, 0, $pos);
$input = (string) substr($input, $pos);
}
}
// 3. Finally, the output buffer is returned as the result of remove_dot_segments.
return $output;
}
Run Code Online (Sandbox Code Playgroud)
不确定为什么你不想使用,realpath但路径名称sanitisation是一个非常简单的概念,沿着以下几行:
/)开头,则将其作为当前工作目录的前缀/,并使其成为绝对路径./与单个一个(a)中././用/./.如果在最后删除./anything/../为/./anything/..如果在最后删除.anything在这种情况下,文本意味着最长的字符序列不是/.
请注意,这些规则应该持续应用,直到它们都不会导致更改为止.换句话说,做所有六个(一次通过).如果字符串改变了,那么回去再做六次(另一次通过).继续这样做,直到字符串与刚刚执行的传递之前相同.
完成这些步骤后,您将拥有可以检查有效模式的规范路径名称.最有可能是任何不能开始的东西../(换句话说,它不会试图超越起点.可能还有其他规则想要应用,但这超出了这个问题的范围.
(a)如果您正在处理//在路径开头处理特殊的系统,请确保/在开头用两个字符替换多个字符.这是POSIX允许(但不强制要求)对倍数进行特殊处理的唯一地方,在所有其他情况下,多个/字符相当于一个字符.